I am trying to write a function that takes in the length of a list and a maximum number value and returns a list that is the length given with numbers between 1 and the given max randomly.
so far I have
(define (randomlist n max)
(cond
[(= n 0)empty]
[else
(cons (build-list n (random 1 max))
(randomlist max (- n 1)))]))
I get an error when I run this and was wondering if anybody could help me out.
One can also use for/list to combine loop and list formation:
(define (randomlist n mx)
(for/list ((i n))
(add1 (random mx))))
Testing:
(randomlist 5 10)
Output:
'(5 9 10 4 7)
(random numbers, hence output is very likely to be different each time).
There are several bugs in your code:
It's a bad idea to call a parameter max, that clashes with a built-in procedure. So I renamed it to mx.
There's absolutely no reason to use build-list, that's not how we build an output list, just cons one element with the rest.
random receives zero or one parameters, not two. The single-parameter version returns an integer in the range 0..n-1, hence we have to add 1 to the result to be in the range 1..n.
You switched the order of the parameters when recursively calling randomlist.
This should take care of the problems:
(define (randomlist n mx)
(cond
[(= n 0) empty]
[else
(cons (+ 1 (random mx))
(randomlist (- n 1) mx))]))
It works as expected:
(randomlist 5 10)
=> '(10 7 1 4 8) ; results will vary, obviously
I wrote this program in Racket which generates 32 random notes from a set of 15 notes and then plays them. The duration of each note should be 0.25 seconds. When I run it gives latency which makes the melody sound off-beat.
How can it run normally?
This is the program:
#lang racket
(provide (all-defined-out))
(require rsound)
(require rsound/piano-tones)
(define-syntax-rule (note y x)
(begin
(play (piano-tone y))
(sleep x)
(stop)))
(define (random-element list)
(list-ref list (random (length list))))
(define-syntax-rule (random-note)
(note (random-element '(40 42 43 45 47 48 50 52 54 55 57 59 60 62 64)) 0.25))
(for ([i 32])
(random-note))
First of all, the notes that come from piano-tone are not really meant to be truncated like that, although you can do it with the clip function.
Second of all, your problem here is that you are relying on how fast your computer will execute code, which is inherently inconsistent.
A much better approach is to use make-pstream. And to queue up the notes to run later. That way there won't be a gap based on your processor in between when notes play.
(Also, as a side note in-range can be used to speed up for loops when you are using them like this.)
Put it all together (using clip to cut your notes off), your program will look something like this (I used magic numbers for brevity, obviously you would want to run through the actual calculations to get 0.25 seconds):
#lang racket
(require rsound
rsound/piano-tones)
(define stream (make-pstream))
(define count 10000)
(define (note y x)
(pstream-queue stream (clip (piano-tone y) 0 10000) count)
(set! count (+ count x)))
(define (random-element list)
(list-ref list (random (length list))))
(define (random-note)
(note (random-element '(40 42 43 45 47 48 50 52 54 55 57 59 60 62 64)) 10000))
(for ([i (in-range 32)])
(random-note))
Finally, if you want to wrap this all up into a single executable, the program will terminate before the queue finishes. So make a busy loop at the end of your program that waits for the queue to finish (by using pstream-queue-callback).
Add this to the end of your program:
(define ok-to-exit? #f)
(pstream-queue-callback stream (lambda () (set! ok-to-exit? #t)) count)
(let loop ()
(sleep 0.1)
(unless ok-to-exit?
(loop)))
I currently have a list like:
((map 9 150) (compass 13 35) (water 150 240) (sandwich 50 16) (rope 50 49))
I am trying to loop through this list get the values in bold and give a total of these value. I have been looking at car and cdr but I can't seem to get these values. Is there a simple way to do this?
That would be the third value in the list or the caddr. Thus
(mapcar #'third products) ; ==> (150 35 240 16 49)
If your list is small you can just use apply:
(apply #'+ (mapcar #'third products)) ; ==> 490
For a larger list (more than 1000) I recommend using reduce
(reduce #'+ (mapcar #'third products)) ; ==> 490
With reduce you can use :key to avoid mapcar:
(reduce #'+ products :key #'third) ; ==> 490
You can also use loop:
(loop :for element :in products
:sum (third element)) ; ==> 490
I started programming in Common Lisp yesterday. Now I want to find the sum of all the multiples of 3 or 5 below 1000. I came up with:
(loop for n from 1 to 1000 when
(or
(eq (mod n 5) 0)
(eq (mod n 3) 0))
(sum n)))
I know that the looping part works (loop for n from 1 to 1000 sum n) to sum the first 1000 numbers. I know that the ((eq (mod n 5) 0) (mod n 3) 0)) parts works. And I know that (or (eq (mod n 5) 0) (eq (mod n 3) 0)) works. So it looks like a robust program to me, but when I run it I get the error:
1=(SUM N) found where keyword expected getting LOOP clause after WHEN current LOOP context: WHEN (OR (EQ (MOD 1000 5) 0)
(EQ (MOD 1000 3) 0))
1#. [Condition of type SB-INT:SIMPLE-PROGRAM-ERROR]
I suspect something is wrong with the (sum n) after the or-statement. But I do not know why that is or how I can solve it. Can someone help me out and get my first Lisp program to work?
sum n, not (sum n)
Don't put sum n in parentheses. The loop macro is its own domain specific language with its own grammar. With it, you'd (loop for ... sum n). The grammar is given in HyperSpec entry on loop in this production:
numeric-accumulation::= {count | counting | sum | summing | }
maximize | maximizing | minimize | minimizing {form | it}
[into simple-var] [type-spec]
If it sounds any better to, you can also write (loop for … summing n). That might read more like a natural English sentence.
=, eql, or zerop, but not eq
It's good practice to get into looking up functions, macros, etc., in the HyperSpec. As Rainer Joswig points out, you shouldn't use eq for comparing numbers. Why? Let's look it up in the HyperSpec. The examples include:
(eq 3 3)
=> true
OR=> false
(eq 3 3.0) => false
(eq 3.0 3.0)
=> true
OR=> false
(eq #c(3 -4) #c(3 -4))
=> true
OR=> false
and the Notes section says (emphasis added):
Objects that appear the same when printed are not necessarily eq to
each other. Symbols that print the same usually are eq to each other
because of the use of the intern function. However, numbers with the
same value need not be eq, and two similar lists are usually not
identical.
An implementation is permitted to make "copies" of characters and
numbers at any time. The effect is that Common Lisp makes no guarantee
that eq is true even when both its arguments are "the same thing" if
that thing is a character or number.
For numbers you need something else. = is a good general numeric comparison, although it does more work here than what you need, because it can compare numbers of different types. E.g., (= 5 5.0) is true. Since you're only concerned about 0, you could use zerop, but that will still do a bit more work than you need, since it will check other numeric types as well. E.g., (zerop #c(0.0 0.0)) is true. In this case, since (mod n …) will be giving you an integer, you can use eql:
The value of eql is true of two objects, x and y, in the folowing
cases:
If x and y are eq.
If x and y are both numbers of the same type and the same value.
If they are both characters that represent the same character.
Thus, you can use (or (eql (mod n 3) 0) (eql (mod n 5) 0)).
Other ways of doing this
Now, your question was about a particular piece of loop syntax, and there were some points to be made about equality operators. However, since some of the other answers have looked at other ways to do this, I think it's worth pointing out that there are much more efficient ways to do this. First, let's look at a way to sum up all the multiples of some number beneath a given limit. E.g., for the number 3 and the inclusive limit 26, we have the sum
?
= 3 + 6 + 9 + 12 + 15 + 18 + 21 + 24
= (3 + 24) + (6 + 21) + (9 + 18) + (12 + 15)
= 27 + 27 + 27 + 27
In general, if you try with a few different numbers, you can work out that for an inclusive limit l and a number n, you'll be adding up pairs of numbers, with an optional half pair if there's a odd number of multiples of n that are less than l. I'm not going to work out the whole derivation, but you can end up with
(defun sum-of-multiples-below-inclusive (limit divisor)
(multiple-value-bind (quotient remainder)
(floor limit divisor)
(let ((pair (+ (- limit remainder) divisor)))
(multiple-value-bind (npairs half-pair)
(floor quotient 2)
(+ (* npairs pair)
(if (oddp half-pair)
(floor pair 2)
0))))))
Then, to find out the sum of the number of multiples less than a given number, you can just substract one from limit:
(defun sum-of-multiples-below (limit divisor)
(sum-of-multiples-below (1- limit) divisor))
Then, to expand to your case, where there are multiple divisors, you'll need to add some of these numbers, and then subtract out the ones that are getting counted twice. E.g., in your case:
(+ (sum-of-multiples-below 1000 3)
(sum-of-multiples-below 1000 5)
(- (sum-of-multiples-below 1000 15)))
;=> 233168
(loop for i from 1 below 1000
when (or (eql 0 (mod i 3))
(eql 0 (mod i 5)))
sum i)
;=> 233168
Now, using time naively can lead to misleading results, but SBCL compiles forms before it evaluates them, so this isn't too terrible. This is a very, very, small micro-benchmark, but take a look at the number of cycles used in each form:
(time (+ (sum-of-multiples-below 1000 3)
(sum-of-multiples-below 1000 5)
(- (sum-of-multiples-below 1000 15))))
Evaluation took:
0.000 seconds of real time
0.000000 seconds of total run time (0.000000 user, 0.000000 system)
100.00% CPU
11,327 processor cycles
0 bytes consed
(time (loop for i from 1 below 1000
when (or (eql 0 (mod i 3))
(eql 0 (mod i 5)))
sum i))
Evaluation took:
0.000 seconds of real time
0.000000 seconds of total run time (0.000000 user, 0.000000 system)
100.00% CPU
183,843 processor cycles
0 bytes consed
Using the closed form is much faster. The different is more pronounced if we use a higher limit. Let's look at 100,000:
(time (+ (sum-of-multiples-below 100000 3)
(sum-of-multiples-below 100000 5)
(- (sum-of-multiples-below 100000 15))))
Evaluation took:
0.000 seconds of real time
0.000000 seconds of total run time (0.000000 user, 0.000000 system)
100.00% CPU
13,378 processor cycles
0 bytes consed
(time (loop for i from 1 below 100000
when (or (eql 0 (mod i 3))
(eql 0 (mod i 5)))
sum i))
Evaluation took:
0.007 seconds of real time
0.004000 seconds of total run time (0.004000 user, 0.000000 system)
57.14% CPU
18,641,205 processor cycles
0 bytes consed
For 10,000,000 the numbers are even more staggering:
(time (+ (sum-of-multiples-below 10000000 3)
(sum-of-multiples-below 10000000 5)
(- (sum-of-multiples-below 10000000 15))))
Evaluation took:
0.000 seconds of real time
0.000000 seconds of total run time (0.000000 user, 0.000000 system)
100.00% CPU
13,797 processor cycles
0 bytes consed
(time (loop for i from 1 below 10000000
when (or (eql 0 (mod i 3))
(eql 0 (mod i 5)))
sum i))
Evaluation took:
0.712 seconds of real time
0.712044 seconds of total run time (0.712044 user, 0.000000 system)
100.00% CPU
1,916,513,379 processor cycles
0 bytes consed
Some of these Project Euler problems are pretty interesting. Some of them have some pretty straightforward naïve solutions that work for small inputs, but don't scale well at all.
I would format the code like this:
(loop for n from 1 below 1000
when (or (zerop (mod n 3))
(zerop (mod n 5)))
sum n))
one line less
when at the start of a line
no need to have or alone on a line
clauses in LOOP don't have parentheses
use below
This kind of Loop macro goes back to the early 70s to Interlisp, long before Common Lisp existed.
Here is a another solution without loop
(defun sum-to-thousand (count result)
(cond ((> count 1000) result)
((= (mod count 3) 0) (sum-to-thousand (+ count 1) (+ count result)))
((= (mod count 5) 0) (sum-to-thousand (+ count 1) (+ count result)))
(t (sum-to-thousand (+ count 1) result))))
May I propose more "lispier" variant:
CL-USER> (defun my-sum (&key (from 1) to dividers (sum 0))
(if (>= from to)
sum
(my-sum :from (1+ from)
:to to
:dividers dividers
:sum (if (some (lambda (x) (zerop (mod from x))) dividers)
(+ sum from)
sum))))
MY-SUM
CL-USER> (my-sum :to 1000 :dividers '(3 5))
233168
(let ((g (* 2 (or (gethash word good) 0)))
(b (or (gethash word bad) 0)))
(unless (< (+ g b) 5)
(max .01
(min .99 (float (/ (min 1 (/ b nbad))
(+ (min 1 (/ g ngood))
(min 1 (/ b nbad)))))))))
What is the problem? It is almost plain english:
Let g be the value of word in the hashtable good (or 0 if not existent there) times 2
(let ((g (* 2 (or (gethash word good) 0)))
and b the value of word in the hashtable bad (or 0 if not existent there).
(b (or (gethash word bad) 0)))
With this in mind, and under the presumption that the sum of g and b is not smaller than 5
(unless (< (+ g b) 5)
return the maximum of either 0.01 or
(max .01
the minimum of either 0.99 or
(min .99
b/nbad divided by the sum of b/nbad and g/ngood (as a float value, and those individual quotients should be at most 1).
(float (/ (min 1 (/ b nbad))
(+ (min 1 (/ g ngood))
(min 1 (/ b nbad)))))))))
Looks like it is trying to calculate a score based on the presence of word in the the hash tables good and bad.
If the word does not exist in a hash table it is given a value of 0, otherwise if it exists in the good table it is weighted by 2 (doubled).
If the score is less than 5 calculate the score (portion below unless) as follows:
score = min(1, b/nbad) / (min(1, g/ngood) + min(1, b/nbad))
max(0.01, min(0.99, score))
I'm not sure what ngood and nbad are but then n indicates to me they are probably counts. It also looks like the code is keeps the calculated score below 5. It also looks like in the score calculation the denominator will be kept to a maximum 2 keep the lower bound of the score to 0.5.
Based on the tags you've used, I would guess (and it is just a guess) that it is trying to calculate a weighting for word based on some kind of frequency(?) counting of the word in good versus bad email.