How to do a While loop in Common LISP? - lisp

Hi I am new in Common Lisp and there aren't any tutorials I can find that relates to my current problem, I have decent knowledge in Java and I tried converting simple programs from Java to Common LISP as an exercise and one particular thing I can't do is a while loop, how do I do it? it always results in UNDEFINED-FUNCTION
TL;DR
how do I do a while loop in common LISP with certain conditions like in Java like this:
while(UserIn > 0)
{
LastD = UserIn % 10;
Sum = Sum + LastD;
Product = Product * LastD;
UserIn = UserIn / 10;
}
if (Sum == Product)
{
System.out.println("\nGiven number is a Spy number");
}
else
{
System.out.println("\nGiven number is not a Spy number");
}
my attempt in common LISP is as follows
(while (> userIn 0)
(setq LastD(mod 10 UserIn))
(setq Product(* LastD Product))
(setq Sum(+ LastD Sum))
(setq UserIn(/ UserIn 10)))
(terpri)
(if (= a b)
(format t "is a spy number")
(format t "is not a spy number"))
)
(Spynumber)
and it keeps on saying: debugger invoked on a UNDEFINED-FUNCTION, thank you!

Common Lisp does not have while form, but it has a much more powerful
loop macro which has the while keyword you want:
(loop while ... do ...)
See also How to do a while loop in LISP

As someone else has said, you can use loop to do that, and that would be the idiomatic approach.
But Lisp is the programmable programming language: if you want while, you can have while:
(defmacro while (test &body decls/tags/forms)
`(do () ((not ,test) (values))
,#decls/tags/forms))
And now
> (let ((i 0))
(while (< i 10)
(print i)
(incf i)))
0
1
2
3
4
5
6
7
8
9
>

Your example program in Java assigns variables that are not declared in the current scope. You have the same problem in Lisp, where you call setq on variables that are not declared. You need to declare variables in Lisp otherwise the behavior is unspecified.
One way to declare variables is to have a let block:
(let ((product 1)
(sum 0))
...
(setq sum (+ sum d)) ;; <-- here SETQ is well-defined
...)
Also, you compute both quotient and the remainder of a division: in Common Lisp functions can return more than one values, and in particular, truncate divides and returns the remainder as a secondary value:
(multiple-value-bind (q r) (truncate u 10)
...)
Recursive approach
It is possible to write loops as recursive procedures, and your example is one of the cases where I find the recursive approach easier to understand. Let's define spy-compute a function of three arguments: a number, the current sum, and the current product of the remainders:
(defun spy-compute (u s p)
...)
The base case corresponds to (= u 0), and in this case the function returns both the sum and the product, as two values:
(defun spy-compute (u s p)
(if (= u 0)
(values s p)
...))
The generat case of recursion consists in dividing u by 10, and calling spy-number recursively with modified sum and products:
(defun spy-compute (u s p)
(if (= u 0)
(values s p)
(multiple-value-bind (q r) (truncate u 10)
(spy-compute q (+ s r) (* p r)))))
This functions needs to be called with the sum initialized to 0 and the product initialized to 1. You can provide a simpler interface to the caller:
(defun spy (n)
(spy-compute n 0 1))
(I fixed a bug here, I had 0 and 1 reversed)
And if you want to check if the number is a spy number, you can define this functions (the p suffix is for "predicate", the naming convention for functions that returns a boolean value):
(defun spyp (n)
(multiple-value-bind (s p) (spy n)
(= s p)))
Example
Having the three functions defined as above, let's trace them and check if 1124 is a spy number (spoiler alert, it is):
* (trace spy-compute spy spyp)
* (spyp 1124)
Here is the execution trace, I added comments manually:
;; root call to SPYP with 1124
0: (SO::SPYP 1124)
;; it calls SPY
1: (SO::SPY 1124)
;; ... which calls SPY-COMPUTE with sum 0 and product 1
2: (SO::SPY-COMPUTE 1124 0 1)
;; DIVIDE by TEN, REMAINDER is 4
;; RECURSE With SUM = SUM + 4 and PRODUCT = PRODUCT * 4
3: (SO::SPY-COMPUTE 112 4 4)
;; DIVIDE by TEN: 112 = 11 * 10 + 2, adjust counters
4: (SO::SPY-COMPUTE 11 6 8)
;; ETC.
5: (SO::SPY-COMPUTE 1 7 8)
;; BASE CASE OF RECURSION, RETURN BOTH COUNTERS
6: (SO::SPY-COMPUTE 0 8 8)
;; NO CHANGE IS MADE TO THE RESULT, IT BUBBLES UP
6: SPY-COMPUTE returned 8 8
5: SPY-COMPUTE returned 8 8
4: SPY-COMPUTE returned 8 8
3: SPY-COMPUTE returned 8 8
2: SPY-COMPUTE returned 8 8
1: SPY returned 8 8
;; CHECK if (= P S), which is T here
0: SPYP returned T
Iterate
Your example can also be written using a loop. In addition other the standard ways of looping, you can also use the iterate package, which contrary to LOOP allows to mix the test clauses (while) with iteration clauses (for):
(ql:quickload :iterate) ;; see https://www.quicklisp.org/beta/
(use-package :iterate)
(defun iter-spy (n)
(iter
(for u :initially n :then q)
(while (> u 0))
(for (values q r) = (truncate u 10))
(sum r :into s)
(multiply r :into p)
(finally (return
(values s p)))))

With do you can loop and assign variables in parallel, the syntax is:
(do ((<var1> <var1-initial-value> <var1-step>)
(<var2> <var2-initial-value> <var2-step>)
...)
((<exit-condition>)
(<final-statement1>)
(<final-statement2>)
...)
(<action1-during-loop>)
(<action2-during-loop>)
...)
So with your code, more or less:
(let* ((UserIn (read))
(UI UserIn))
(do* ((LastD (rem UserIn 10) (rem UserIn 10))
(Sum 0 (+ Sum LastD))
(Product 1 (* Product LastD))
(UserIn UserIn (truncate UserIn 10)))
((<= UserIn 0)
(format t "~&LastD: ~f, Sum: ~f, Product: ~f, UserIn: ~f"
LastD Sum Product UserIn)
(if (= Sum Product)
(format t "~&~A is Spy number" UI)
(format t "~&~A is Not Spy number" UI)))
(format t "~&LastD: ~f, Sum: ~f, Product: ~f, UserIn: ~f"
LastD Sum Product UserIn)))
> LastD: 4.0, Sum: 0.0, Product: 1.0, UserIn: 1124.0
> LastD: 4.0, Sum: 4.0, Product: 4.0, UserIn: 112.0
> LastD: 2.0, Sum: 6.0, Product: 8.0, UserIn: 11.0
> LastD: 1.0, Sum: 7.0, Product: 8.0, UserIn: 1.0
> LastD: 1.0, Sum: 8.0, Product: 8.0, UserIn: 0.0
> 1124 is Spy number
> LastD: 2.0, Sum: 0.0, Product: 1.0, UserIn: 12.0
> LastD: 2.0, Sum: 2.0, Product: 2.0, UserIn: 1.0
> LastD: 1.0, Sum: 3.0, Product: 2.0, UserIn: 0.0
> 12 is Not Spy number
For some code snippets you can visit http://rosettacode.org/wiki/Rosetta_Code.

(defmacro while (condition &rest body)
`(loop while ,condition
do (progn
,#body)))

Related

Number of digits in a number with lisp using cond

So, I know that there is a solution using the if statement which is the following
(defun numdigits (n)
(if (< -10 n 10)
1
(1+ (numdigits (truncate n 10)))))
But I'm trying to deepen my knowledge and to understand to go for transforming if statements to the cond statement. SO I tried it out using the cond statement, but I receive an error, and quite honestly, I don't know why.
Here's what I did:
(defun nbDigits (digit)
(cond
((> 0 (- digit 10)) 1)
(t (1 + (nbDigits (truncate digit 10))))
)
)
The logic I'm having is:
If 0 is greater than x-10, return 1 ( as this means the number is smaller than 10). Else, return 1 + nbDigits(the quotient of the digit when it's divided by 10), which should go until it reaches the base case.
I'm getting the error:
Illegal argument in functor position: 1 in (1 + (NBDIGITS (TRUNCATE DIGIT 10))).
But I don't understand how to go about this error.. Did I do a wrong call?
Thanks.
A simple space between 1 and + is changing the function 1+ into two elements. Remove that space and you are done.
Incidentally, simplify your math by writing (< digit 10) instead of (> 0 (- digit 10))
In the end it should look like this:
(defun nbDigits (digit)
(cond
((< digit 10) 1)
(t (1+ (nbDigits (truncate digit 10))))
)
)

Lisp, sub total of a numbers in a nested list

i have a problem that i just cant work out,
the user enters a list ie
(total-cost
'((anItem 2 0.01)
(item 3 0.10)
(anotherItem 4 4.10)
(item 5 2.51)))
i need to add the number on the end together and then return the result
my current code returns the code after each addition. and also throws a error about unexpected type
(defun total-cost (list)
(loop with sum = 0
for x in list
collect (setf sum (+ sum (last x)))
)
)
Error: (0.01)' is not of the expected typeNUMBER'
Any help is appreciated
Thanks Dale
Using LOOP:
CL-USER 19 > (loop for (nil nil number) in '((anItem 2 0.01)
(item 3 0.10)
(anotherItem 4 4.10)
(item 5 2.51))
sum number)
6.72
REDUCE is another option:
CL-USER 20 > (reduce '+
'((anItem 2 0.01)
(item 3 0.10)
(anotherItem 4 4.10)
(item 5 2.51))
:key 'third)
6.72
Loop has a keyword sum for summing so you don't have to have an explicit variable nor use setf:
(defun total-cost (list)
(loop for x in list sum (third x)))
As Chris said, use (car (last x)) if the number you're looking for is always the last one. Or you can use (third x) as in my example if it's always the third one.
Also, note that the use of collectis wrong if your aim is to return the sum only; your example (corrected) returns
(0.01 0.11 4.21 6.7200003)
whereas mine returns
6.7200003
Note that if you want so escape the rounding errors as much as possible you need to use an exponent marker to make them double-floats for example:
(total-cost '((anItem 2 0.01D0)
(item 3 0.10D0)
(anotherItem 4 4.10D0)
(item 5 2.51D0)))
=> 6.72D0
last returns the last cons cell in the list, not its value. You need to use (car (last x)) instead.
Just in case you want the code to give you a precise result rather then being short:
(defun kahan-sum (floats)
(loop
:with sum := 0.0 :and error := 0.0
:for float :in floats
:for epsilon := (- float error)
:for corrected-sum := (+ sum epsilon) :do
(setf error (- corrected-sum sum epsilon) sum corrected-sum)
:finally (return sum)))
(defun naive-sum (floats) (loop :for float :in floats :sum float))
(let ((floats (loop :repeat 1000 :collect (- (random 1000000.0) 1000000.0))))
(format t "~&naive sum: ~f, kahan sum: ~f" (naive-sum floats) (kahan-sum floats)))
;; naive sum: -498127420.0, kahan sum: -498127600.0
Read more about why it works like this here: http://en.wikipedia.org/wiki/Kahan_summation_algorithm
Coming late to the party... How about a little lisping instead of looping? ;-)
(defun sum-3rd (xs)
(let ((sum 0))
(dolist (x xs sum)
(incf sum (nth 2 x)))))

Convert decimal number to octal in Lisp

I'm trying to write a function in Common Lisp to convert a base 10 number into a base 8 number, represented as a list, recursively.
Here's what I have so far:
(defun base8(n)
(cond
((zerop (truncate n 8)) (cons n nil))
((t) (cons (mod n 8) (base8 (truncate n 8))))))
This function works fine when I input numbers < 8 and > -8, but the recursive case is giving me a lot of trouble. When I try 8 as an argument (which should return (1 0)), I get an error Undefined operator T in form (T).
Thanks in advance.
Just for fun, here's a solution without recursion, using built-in functionality:
(defun base8 (n)
(reverse (coerce (format nil "~8R" n) 'list)))
It seems you have forgotten to (defun t ...) or perhaps it's not the function t you meant to have in the cond? Perhaps it's t the truth value?
The dual namespace nature of Common Lisp makes it possible for t to both be a function and the truth value. the difference is which context you use it and you clearly are trying to apply t as a function/macro.
Here is the code edited for the truth value instead of the t function:
(defun base8(n)
(cond
((zerop (truncate n 8)) (cons n nil))
(t (cons (mod n 8) (base8 (truncate n 8))))))
(base8 8) ; ==> (0 1)

Common Lisp: "no non-white-space characters in string"

For Project Euler Problem 8, I am told to parse through a 1000 digit number.
This is a brute-force Lisp solution, which basically goes through every 5 consecutive digits and multiplies them from start to finish, and returns the largest one at the end of the loop.
The code:
(defun pep8 ()
(labels ((product-of-5n (n)
(eval (append '(*)
(loop for x from n to (+ n 5)
collect (parse-integer
1000digits-str :start x :end (+ x 1)))))))
(let ((largestproduct 0))
(do ((currentdigit 0 (1+ currentdigit)))
((> currentdigit (- (length 1000digits-str) 6)) (return largestproduct))
(when (> (product-of-5n currentdigit) largestproduct)
(setf largestproduct (product-of-5n currentdigit)))))))
It compiles without any warnings, but upon running it I get:
no non-whitespace characters in string "73167176531330624919225119674426574742355349194934...".
[Condition of type SB-INT:SIMPLE-PARSE-ERROR]
I checked to see if the local function product-of-5n was working by writing it again as a global function:
(defun product-of-5n (n)
(eval (append '(*)
(loop for x from n to (+ n 5)
collect (parse-integer
1000digits-str :start x :end (+ x 1))))))
This compiled without warnings and upon running it, appears to operate perfectly. For example,
CL_USER> (product-of-5n 1) => 882
Which appears to be correct since the first five digits are 7, 3, 1, 6 and 7.
As for 1000digits-str, it was simply compiled with defvar, and with Emacs' longlines-show-hard-newlines, I don't think there are any white-space characters in the string, because that's what SBCL is complaining about, right?
I don't think there are any white-space characters in the string, because that's what SBCL is complaining about, right?
The error-message isn't complaining about the presence of white-space, but about the absence of non-white-space. But it's actually a bit misleading: what the message should say is that there's no non-white-space in the specific substring to be parsed. This is because you ran off the end of the string, so were parsing a zero-length substring.
Also, product-of-5n is not defined quite right. It's just happenstance that (product-of-5n 1) returns the product of the first five digits. Strings are indexed from 0, so (product-of-5n 1) starts with the second character; and the function iterates from n + 0 to n + 5, which is a total of six characters; so (product-of-5n 1) returns 3 × 1 × 6 × 7 × 1 × 7, which happens to be the same as 7 × 3 × 1 × 6 × 7 × 1.
EVAL is not a good idea.
Your loop upper bound is wrong.
Otherwise I tried it with the number string and it works.
It's also Euler 8, not 9.
This is my version:
(defun euler8 (string)
(loop for (a b c d e) on (map 'list #'digit-char-p string)
while e maximize (* a b c d e)))
since I don't know common lisp, I slightly modified your code to fit with elisp. As far as finding bugs go and besides what have been said ((product-of-5n 1) should return 126), the only comment I have is that in (pep8), do length-4 instead of -6 (otherwise you loose last 2 characters). Sorry that I don't know how to fix your parse-error (I used string-to-number instead), but here is the code in case you find it useful:
(defun product-of-5n (n) ;take 5 characters from a string "1000digits-str" starting with nth one and output their product
(let (ox) ;define ox as a local variable
(eval ;evaluate
(append '(*) ;concatenate the multiplication sign to the list of 5 numbers (that are added next)
(dotimes (x 5 ox) ;x goes from 0 to 4 (n is added later to make it go n to n+4), the output is stored in ox
(setq ox (cons ;create a list of 5 numbers and store it in ox
(string-to-number
(substring 1000digits-str (+ x n) (+ (+ x n) 1) ) ;get the (n+x)th character
) ;end convert char to number
ox ) ;end cons
) ;end setq
) ;end dotimes, returns ox outside of do, ox has the list of 5 numbers in it
) ;end append
) ;end eval
) ;end let
)
(defun pep8 () ;print the highest
(let ((currentdigit 0) (largestproduct 0)) ;initialize local variables
(while (< currentdigit (- (length 1000digits-str) 4) ) ;while currentdigit (cd from now on) is less than l(str)-4
;(print (cons "current digit" currentdigit)) ;uncomment to print cd
(when (> (product-of-5n currentdigit) largestproduct) ;when current product is greater than previous largestproduct (lp)
(setq largestproduct (product-of-5n currentdigit)) ;save lp
(print (cons "next good cd" currentdigit)) ;print cd
(print (cons "with corresponding lp" largestproduct)) ;print lp
) ;end when
(setq currentdigit (1+ currentdigit)) ;increment cd
) ;end while
(print (cons "best ever lp" largestproduct) ) ;print best ever lp
) ;end let
)
(setq 1000digits-str "73167176531330624919")
(product-of-5n 1)
(pep9)
which returns (when ran on the first 20 characters)
"73167176531330624919"
126
("next good cd" . 0)
("with corresponding lp" . 882)
("next good cd" . 3)
("with corresponding lp" . 1764)
("best ever lp" . 1764)
I've done this problem some time ago, and there's one thing you are missing in the description of the problem. You need to read consequent as starting at any offset into a sting, not only the offsets divisible by 5. Therefore the solution to the problem will be more like the following:
(defun pe-8 ()
(do ((input (remove #\Newline
"73167176531330624919225119674426574742355349194934
96983520312774506326239578318016984801869478851843
85861560789112949495459501737958331952853208805511
12540698747158523863050715693290963295227443043557
66896648950445244523161731856403098711121722383113
62229893423380308135336276614282806444486645238749
30358907296290491560440772390713810515859307960866
70172427121883998797908792274921901699720888093776
65727333001053367881220235421809751254540594752243
52584907711670556013604839586446706324415722155397
53697817977846174064955149290862569321978468622482
83972241375657056057490261407972968652414535100474
82166370484403199890008895243450658541227588666881
16427171479924442928230863465674813919123162824586
17866458359124566529476545682848912883142607690042
24219022671055626321111109370544217506941658960408
07198403850962455444362981230987879927244284909188
84580156166097919133875499200524063689912560717606
05886116467109405077541002256983155200055935729725
71636269561882670428252483600823257530420752963450"))
(tries 0 (1+ tries))
(result 0))
((= tries 5) result)
(setq result
(max result
(do ((max 0)
(i 0 (+ 5 i)))
((= i (length input)) max)
(setq max
(do ((j i (1+ j))
(current 1)
int-char)
((= j (+ 5 i)) (max current max))
(setq int-char (- (char-code (aref input j)) 48))
(case int-char
(0 (return max))
(1)
(t (setq current (* current int-char))))))))
input (concatenate 'string (subseq input 1) (subseq input 0 1)))))
It's a tad ugly, but it illustrates the idea.
EDIT sorry, I've confused two of your functions. So that like was incorrect.

How to loop using recursion in ACL2?

I need to make something like this but in ACL2:
for (i=1; i<10; i++) {
print i;
}
It uses COMMON LISP, but I haven't any idea how to do this task...
We can't use standard Common Lisp constructions such as LOOP, DO. Just recursion.
I have some links, but I find it very difficult to understand:
Gentle Intro to ACL2 Programming
The section "Visiting all the natural numbers from n to 0" in A Gentle Introduction to ACL2 Programming explains how to do it.
In your case you want to visit numbers in ascending order, so your code should look something like this:
(defun visit (n max ...)
(cond ((> n max) ...) ; N exceeds MAX: nothing to do.
(t . ; N less than or equal to MAX:
. n ; do something with N, and
.
(visit (+ n 1) max ...) ; visit the numbers above it.
.
.
.)))
A solution that uses recursion:
> (defun for-loop (from to fn)
(if (<= from to)
(progn
(funcall fn from)
(for-loop (+ from 1) to fn))))
;; Test
> (for-loop 1 10 #'(lambda (i) (format t "~a~%" i)))
1
2
3
4
5
6
7
8
9
10
NIL
(defun foo-loop (n)
(cond ((zp n) "done")
(t (prog2$ (cw "~x0" n)
(foo-loop (1- n)))))
(foo-loop 10)
You can redo the termination condition and the recursion to mimic going from 1 to 10.