I'm kinda new in scheme syntax... I'm trying to make a simple program where you input an integer, if the integer is even do something and if it's odd do something else.
I was able to do this part. Now, I need to make a loop where I can decrement the number until it equals to 1.
Here is my code :
#lang racket
(define (even? n)
(if (eqv? n 0) #t
(odd? (- n 1))))
(define (odd? n)
(if (eqv? n 0) #f
(even? (- n 1))))
; this is the function that i wanted to be inside the loop
(define (sequence n)
(cond
[(even? n) n( / n 2)]
[(odd? n) n(+(* n 3) 1) ] )
)
(sequence 5)
The output should be a sequence of numbers. In other words, it should be inside a list.
An output list is built by consing each of the elements that are part of the list and then advancing the recursion over the input, until the input is exhausted (in your case, when the number n is one). By successively consing elements at the head of the list and ending the recursion with a null value, a new proper list is created and returned at the end of the procedure execution. Here's how:
(define (sequence n)
(cond [(= n 1) ; if n=1, it's the exit condition
(list n)] ; return a list with last element
[(even? n) ; if n is even
(cons n (sequence (/ n 2)))] ; cons n and advance the recursion
[(odd? n) ; if n is odd
(cons n (sequence (+ (* n 3) 1)))])) ; cons n and advance the recursion
The above will return a list with the Collatz sequence for the given number n:
(sequence 6)
=> '(6 3 10 5 16 8 4 2 1)
As a side note: the procedures even? and odd? are standard in Scheme and you don't have to redefine them.
Related
I've been fiddling with Lisp programs for a little while and one thing that I can never seem to figure out is how to use a loop on a list inside a function. I'm trying to create a function that will take a list as the parameters while using a do... loop. I know how to do it with if statements but now I need to use a loop. Does anyone have a clue on how to do that?
(defun maximum (a_list)
(if (= (length a_list) 1)
(car a_list)
(if (> (car a_list) (maximum (cdr a_list)))
(car a_list)
(maximum (cdr a_list))))
(format t "~d" a_list))
Here's what I have so far on the if statements. They might not work right but at least they work.
Here another set of possibilities, in addition to those proposed in another answers.
First of all, when writing a function, one should also test for special cases, while you do not check for an empty list. So the structure of the function could be something of this type:
(defun maximum (l)
(if (null l)
nil ; or give an error
...normal solution...))
In case of returning nil, this structure in Common Lisp is identical to the following one, given that and evaluates its arguments in sequence, and returns nil as soon as an argument is evaluated to nil, otherwise returns the value of the last argument:
(defun maximum (l)
(and l ...normal solution...))
Here the alternative solutions.
Without loop or recursion, with predefined functions reduce (manual) and max (manual).
(defun maximum (l)
(and l (reduce #'max l)))
With the construct dolist (manual), that iterates a variable over a list:
(defun maximum (l)
(and l (let ((result (car l)))
(dolist (x (cdr l) result)
(when (> x result)
(setf result x))))))
And finally, with a compact version of do (manual):
(defun maximum (l)
(and l (do ((maximum-so-far (car l) (max (pop l) maximum-so-far)))
((null l) maximum-so-far))))
With loop the solution is trivial:
(loop for x in '(1 2 7 4 5) maximize x)
I assume therefore that what you intend to do is to write the function with a do loop. In this case you have to traverse the list keeping track of the maximum element so far, and updating this value if you find a larger value:
(setq list '(1 2 7 4 5))
(do* ((l list (cdr l))
(x (car l) (car l))
(max x) )
((null l) max)
(if (> x max)
(setq max x) ))
(defun maximum (list)
(let ((result)) ;; short for ((result nil))
(dolist (x list)
(if result
(when (> x result)
(setf result x))
(setf result x)))
result))
(dolist (x list) ... ) is like Python's [... for x in list]
It is typical imperative style to create a variable with
let and setf to it to change its value.
I'm trying to write a function to determine whether a word is palindrome or not. I make this but it always returns "Is not a palindrome". I don't know what is happening.
(defun palindromo (X)
(setq i 0)
(setq j (- (length X) 1))
(setq bandera 0)
(loop while (< j i)
do
(when (char= (char X i) (char X j))
(+ i 1)
(- j 1)
(setq bandera 1))
(unless (char/= (char X i) (char X j))
(setq bandera 0)
)
)
(cond
((equal 0 bandera) (write "Is not a palindrome"))
((equal 1 bandera) (write "Is a palindrome"))
)
)
How can I fix this?
Loop problem
Your loop termination test is while (< j i), but you previously set i and j to respectively the index of the first and last character. That means that (<= i j). You never execute the body of the loop, and bandera is never modified from its initial value, 0.
Infinite loop problem
But suppose you fix your test so that it becomes (< i j), then your loop becomes an infinite loop, because you never mutates either i nor j in the body of your loop. The two expressions (+ i 1) and (- j 1) only computes the next indices, but do not change existing bindings. You would have to use setq, just as you did above.
Invalid use of SETQ
By the way, you cannot introduce variables with setq: it is undefined what happens when trying to set a variable that is not defined. You can introduce global variables with defvar, defparameter, and local variables with, among others, let, let* and the loop keyword with.
I assume your Common Lisp implementation implicitly defined global variables when you executed or compiled (setq i 0) and other assignments. But this is far from ideal since now your function depends on the global state and is not reentrant. If you called palindromo from different threads, all global variables would be modified concurrently, which would give incorrect results. Better use local variables.
Boolean logic
Do not use 0 and 1 for your flag, Lisp uses nil as false and everything else as true for its boolean operators.
Confusing tests
In the loop body, you first write:
(when (char= (char X i) (char X j)) ...)
Then you write:
(unless (char/= (char X i) (char X j)) ...)
Both test the same thing, and the second one involves a double-negation (unless not equal), which is hard to read.
Style
You generally do not want to print things from utility functions.
You should probably only return a boolean result.
The name of X is a little bit unclear, I'd would have used string.
Try to use the conventional way of formatting your Lisp code. It helps to use an editor which auto-indents your code (e.g. Emacs). Also, do not leave dangling parentheses on their own lines.
Rewrite
(defun palindromep (string)
(loop with max = (1- (length string))
for i from 0
for j downfrom max
while (< i j)
always (char= (char string i)
(char string j))))
I added a p to palindrome by convention, because it is a predicate.
The with max = ... in the loop defines a loop variable which holds the index of the last character (or -1 if string is empty).
i is a loop variable which increments, starting from 0
j is a loop variable which decrements, starting from max
the whileis a termination test
always evaluates a form at each execution of the loop, and check whether it is always true (non-nil).
Actually, no externally defined loop is needed for finding out, whether a string is palindromic or not. [ Remark: well, I thought that in the beginning. But as #coredump and #jkiiski pointed out, the reverse function slows down the procedure, since it copies the entire string once. ]
Use:
(defun palindromep (s)
(string= s (reverse s)))
[ This function will be way more efficient than your code
and it returns T if s is palindromic, else NIL.] (Not true, it only saves you writing effort, but it is less efficient than the procedure using loop.)
A verbose version would be:
(defun palindromep (s)
(let ((result (string= s (reverse s))))
(write (if result
"Is a palindrome"
"Is not a palindrome"))
result))
Writes the answer you wish but returns T or NIL.
The naming convention for a test function returning T or NIL is to end the name with p for 'predicate'.
The reverse function is less performant than the while loop suggested by #coredump
This was my beginner attempt to test the speed [not recommendable]:
;; Improved loop version by #coredump:
(defun palindromep-loop (string)
(loop with max = (1- (length string))
for i from 0
for j downfrom max
while (< i j)
always (char= (char string i)
(char string j))))
;; the solution with reverse
(defun palindromep (s)
(string= s (reverse s)))
;; the test functions test over and over the same string "abcdefggfedcba"
;; 10000 times over and over again
;; I did the repeats so that the measuring comes at least to the milliseconds
;; range ... (but it was too few repeats still. See below.)
(defun test-palindrome-loop ()
(loop repeat 10000
do (palindromep-loop "abcdefggfedcba")))
(time (test-palindrome-loop))
(defun test-palindrome-p ()
(loop repeat 10000
do (palindromep "abcdefggfedcba")))
(time (test-palindrome-p))
;; run on SBCL
[55]> (time (test-palindrome-loop))
Real time: 0.152438 sec.
Run time: 0.152 sec.
Space: 0 Bytes
NIL
[56]> (time (test-palindrome-p))
Real time: 0.019284 sec.
Run time: 0.02 sec.
Space: 240000 Bytes
NIL
;; note: this is the worst case that the string is a palindrome
;; for `palindrome-p` it would break much earlier when a string is
;; not a palindrome!
And this is #coredump's attempt to test the speed of the functions:
(lisp-implementation-type)
"SBCL"
(lisp-implementation-version)
"1.4.0.75.release.1710-6a36da1"
(machine-type)
"X86-64"
(defun palindromep-loop (string)
(loop with max = (1- (length string))
for i from 0
for j downfrom max
while (< i j)
always (char= (char string i)
(char string j))))
(defun palindromep (s)
(string= s (reverse s)))
(defun test-palindrome-loop (s)
(sb-ext:gc :full t)
(time
(loop repeat 10000000
do (palindromep-loop s))))
(defun test-palindrome-p (s)
(sb-ext:gc :full t)
(time
(loop repeat 10000000
do (palindromep s))))
(defun rand-char ()
(code-char
(+ #.(char-code #\a)
(random #.(- (char-code #\z) (char-code #\a))))))
(defun generate-palindrome (n &optional oddp)
(let ((left (coerce (loop repeat n collect (rand-char)) 'string)))
(concatenate 'string
left
(and oddp (list (rand-char)))
(reverse left))))
(let ((s (generate-palindrome 20)))
(test-palindrome-p s)
(test-palindrome-loop s))
Evaluation took:
4.093 seconds of real time
4.100000 seconds of total run time (4.068000 user, 0.032000 system)
[ Run times consist of 0.124 seconds GC time, and 3.976 seconds non-GC time. ]
100.17% CPU
9,800,692,770 processor cycles
1,919,983,328 bytes consed
Evaluation took:
2.353 seconds of real time
2.352000 seconds of total run time (2.352000 user, 0.000000 system)
99.96% CPU
5,633,385,408 processor cycles
0 bytes consed
What I have learned from that:
- Test more rigorously, repeat as often as necessary (range of seconds)
- do random generation and then test in parallel
Thank you very much for the nice example #coredump! And for the remark #jkiiski!
Common Lisp has a powerful Loop macro built in. It's really useful and powerful, and I use it quite often.
I've also heard of a very similar thing, called Iterate. It look really similar to Loop, but has more Lispy feel to it. What are the differences between these two? May there be any reason to switch to any of these, apart from simple preference of style?
Some things that are unique to iterate:
No rigid order for clauses
loop requires that all for clauses appear before the loop body, for example before while. It's ok for iter:
(iter (for x in '(1 2 99)
(while (< x 10))
(for y = (print x))
(collect (list x y)))
Accumulating clauses can be nested
collect, appending and the like can appear anywhere:
(iter (for x in '(1 2 3))
(case x
(1 (collect :a))
(2 (collect :b))))
finding
;; Finding the longest list in a list of lists:
(iter (for lst in '((a) (b c d) (e f)))
(finding lst maximizing (length lst)))
=> (B C D)
;; The rough equivalent in LOOP:
(loop with max-lst = nil
with max-key = 0
for lst in '((a) (b c d) (e f))
for key = (length lst)
do
(when (> key max-key)
(setf max-lst lst
max-key key))
finally (return max-lst))
=> (B C D)
https://common-lisp.net/project/iterate/ first example
Finding the minimum of x^2 - 4x + 1 in an interval:
(iter (for x from -5 to 5 by 1/100)
(finding x minimizing (1+ (* x (- x 4)))))
2
©Common Lisp Recipes p.198
next-iteration
it is like "continue" and loop doesn't have it.
iter also has first-iteration-p and (if-first-time then else).
https://web.archive.org/web/20170713081006/https://items.sjbach.com/211/comparing-loop-and-iterate
generators
generate and next. A generator is lazy, it goes to the next value when said explicitly.
(iter (for i in '(1 2 3 4 5))
(generate c in-string "black")
(if (oddp i) (next c))
(format t "~a " c))
b b l l a
NIL
https://sites.google.com/site/sabraonthehill/loop-v-iter
previous
(iter (for el in '(a b c d e))
(for prev-el previous el)
(collect (list el prev-el)))
=> ((A NIL) (B A) (C B) (D C) (E D))
although it is doable with loop's parallel binding and:
(loop for el in '(a b c d e)
and prev-el = nil then el
collect (list el prev-el))
more clauses
in-string
LOOP offers collecting, nconcing, and appending. ITERATE has these and also adjoining, unioning, nunioning, and accumulating.
(iter (for el in '(a b c a d b))
(adjoining el))
=> (A B C D)
(adjoin is a set operation)
LOOP has summing, counting, maximizing, and minimizing. ITERATE also includes multiplying and reducing. reducing is the generalized reduction builder:
(iter (with dividend = 100)
(for divisor in '(10 5 2))
(reducing divisor by #'/ initial-value dividend))
=> 1
https://web.archive.org/web/20170713105315/https://items.sjbach.com/280/extending-the-iterate-macro
It is extensible
(defmacro dividing-by (num &keys (initial-value 0))
`(reducing ,num by #'/ initial-value ,initial-value))
(iter (for i in '(10 5 2))
(dividing-by i :initial-value 100))
=> 1
but there is more.
https://common-lisp.net/project/iterate/doc/Rolling-Your-Own.html#Rolling-Your-Own
https://web.archive.org/web/20170713105315/https://items.sjbach.com/280/extending-the-iterate-macro where in the Appendix, we see two examples of loop extensions. But they are not portable really, the code is full of #+(or allegro clisp-aloop cmu openmcl sbcl scl) (ansi-loop::add-loop-path …, sb-loop::add-loop-path etc.
Stuff missing in iterate
No parallel binding like loop's and, but not needed?.
I'm probably missing here.
But that's not all, there are more differences.
I've recently started learning lisp and i thought an interesting problem would be the Count Change algorithm which has been attempted many times however i've found it very difficult to even sort out how to approach this and thought i would try using loops but it just isn't working. I'll put my two useless attempts below but if anyone has any suggestions of even how i should be thinking about this problem in terms of lisp it would be really appreciated.
I would much prefer to use a recursive solution aswell.
I've been looking through the questions on here about counting change but they all tend to be object orientated while i need something more functional.
It's not home work, just private study!
(defun dollar (amount)
(let ((l 0) (j 0) (array (make-array '(5 10 20 50 100 200 500 1000 2000 5000 100000))) (results (make-array 50 :initial-element nil))
(do (l 10 (+ l 1))
(do ((= j (aref array l)) amount (+ j 1))
(+ (aref array j) (- (aref results j) (aref array l))))))
))
(defun coin-change (amount coins)
(cond ((< amount 0) 0)
((= amount 5) 1)
((null coins) 0)
(t (+ (make-change-with-coins (- amount (car coins)) coins)
(make-change-with-coins amount (cdr coins)))))
)
sample input would be (coin-change 20 '(5 10 20 50 100 200 500 1000 2000 5000 100000)) which would return 4
Standard formatting helps getting the code structure right. Reading some kind of documentation about a new language helps even more.
This is what you have written:
(defun dollar (amount)
(let ((l 0)
(j 0)
(array (make-array '(5 10 20 50 100 200 500 1000 2000 5000 100000)))
(results (make-array 50 :initial-element nil))
(do (l 10 (+ l 1))
(do ((= j (aref array l)) amount (+ j 1))
(+ (aref array j) (- (aref results j) (aref array l))))))))
Dollar doesn't get the semantics right. Make-array takes the dimensions as first argument, and you most likely wanted the do form as a body of the let. I'd use a vector literal here.
(defun dollar (amount)
(let ((l 0)
(j 0)
(array #(5 10 20 50 100 200 500 1000 2000 5000 100000))
(results (make-array 50 :initial-element nil)))
(do (l 10 (+ l 1))
(do ((= j (aref array l)) amount (+ j 1))
(+ (aref array j) (- (aref results j) (aref array l)))))))
Do takes first a list of bindings, then a form containing an end condition and return forms and finally forms that form a body.
(defun dollar (amount)
(let ((l 0)
(j 0)
(array #(5 10 20 50 100 200 500 1000 2000 5000 100000))
(results (make-array 50 :initial-element nil)))
(do ((l 10 (+ l 1)))
(#| end condition here |#
#| some more forms
that return something |#)
(do ((= j (aref array l)) ; uh, so this binds the variable "=" to j
; and updates it to (aref array l) on iteration
amount ; an empty binding, initially nil
(+ j 1)) ; binds the variable "+" to j and updates it to 1
(+ ; tries to evaluate the variable "+" as a form...
(aref array j) ; no effect
(- (aref results j) (aref array l))))))) ; would return this
I tried to correct the shape of the outer do and annotated the inner do. It makes no sense at all, as you can see.
(defun coin-change (amount coins)
(cond ((< amount 0) 0)
((= amount 5) 1)
((null coins) 0)
(t (+ (make-change-with-coins (- amount (car coins)) coins)
(make-change-with-coins amount (cdr coins))))))
This looks at least semantically correct, but I cannot tell how it is supposed to work (and I don't know what make-change-with-coins does).
I think it would be prudent to perhaps read a good introductory book first (I like Practical Common Lisp) and peruse the Common Lisp Hyperspec (CLHS).
It's not clear to me what the first function is supposed to do.
The second one almost ok, this is a fixed version:
(defun coin-change (amount coins)
(cond
((< amount 0) 0)
((= amount 0) 1)
((= (length coins) 0) 0)
(t (+ (coin-change (- amount (first coins)) coins)
(coin-change amount (rest coins))))))
The idea is:
A negative amount cannot be matched (0 ways)
Zero can be matched in exactly one way (not giving any coin)
If amount is >0 and we've no coin types remaining then there are no ways
Otherwise we can either A) give one piece of the first coin type and count how many ways we can match the remaining part, B) computing the ways without using the first coin type. The answer is A+B
Note that this is going to give huge computing times for large amounts because it doesn't take advantage of the important fact that the number of ways to match a certain amount starting with a certain coin type doesn't depend on how we got to this amount (i.e. the past history).
By adding caching you can get a dynamic-programming solution that is much faster because does each computation only once.
I am a complete novice to LISP I have the book Practical Common Lisp by Peter Seibel, but I couldn't find an answer to my question.
So basically how do I get this to return the value of the last ":do"
(defun averages (numbers)
(loop :for i :in numbers :sum i :into x :do (/ x (length numbers))))
Please bare in mind that I haven't been doing this very long.
Nor am I very aware of the unwritten do's and don't of Stackoverflow.
Use finally:
(defun averages (numbers)
(loop :for i :in numbers :sum i :into x
:finally (return (/ x (length numbers)))))
To avoid traversing the list twice, you can do (as suggested by #mark-reed and #joshua-taylor)
(defun averages (numbers)
(loop :for n :in numbers :sum n :into x :count t :into len
:finally (return (/ x len))))
but it will probably not make much difference performance-wise.
PS. You might want to consider CLOCC/CLLIB/math.lisp for your basic statistical needs.
If you don't make use of advanced features like multiple variables inside the LOOP, it's easy to simplify it:
(defun averages (numbers)
(loop for i in numbers sum i into x
finally (return (/ x (length numbers)))))
Just take advantage that the LOOP form returns the sum:
(defun averages (numbers)
(/ (loop for i in numbers sum i)
(length numbers)))
It might also be useful to check for an empty list of numbers first.