Common Lisp - type checking two variables - lisp

Hi I'm a beginner in Common Lisp. I want to check if two variables are integers. If both n and m are integers I want to it to return - if it is negative, 0 if it is zero, + if it is positive and NIL if it is not an integer for both n and m. I figured out how to do this with one variable but I can't seem to figure out how to do it with two variables. Thanks.
This is the code that takes a numeric argument and returns - if it is negative, 0 if it is zero, + if it is positive and NIL if its not an integer:
(defun sign (n)
(if(typep n 'integer)
(cond ((< n 0) '-)
((= n 0) 0)
((> n 0) '+))))
The output for each case is:
CL-USER> (sign 3)
+
CL-USER> (sign -3)
-
CL-USER> (sign 0)
0
CL-USER> (sign 3.3)
NIL
This is the code I have for checking two variables which I want it to check if n and m are integers and if n and m are positive, negative or a zero:
(defun sign (n m)
(if (and (typep n 'integer) (typep m 'integer))
(cond (and ((< n 0) '-) ((< m 0) '-))
(and ((= n 0) 0) ((= m 0) 0))
(and ((> n 0) '+) ((> m 0) '+)) ))))

Remember basic Lisp syntax. Function calls and some basic expressions are written as
(operator argument-0 argument-1 ... argument-n)
Right?
open parenthesis, operator, argument-0 argument-1 ... argument-n, closing parenthesis.
Now if we have (< n 0) and (< m 0) how would an AND expressions look like?
(and (< n 0) (< m 0))
But you write:
and ((< n 0) '-) ((< m 0) '-)
You have these mistakes:
no parentheses around the AND expression.
extra parenthesis around the argument expressions.
'- mixed into the argument expressions.
Now COND expects:
(COND (testa1 forma0 forma1 ... forman)
(testb1 formb1 formb1 ... formbn)
...
(testm1 formm0 formm1 ... formmn))
So instead of
(defun sign (n m)
(if (and (typep n 'integer) (typep m 'integer))
(cond (and ((< n 0) '-) ((< m 0) '-))
(and ((= n 0) 0) ((= m 0) 0))
(and ((> n 0) '+) ((> m 0) '+)))))
Btw, there was an extra parenthesis at the end.
We write:
(defun sign (n m)
(if (and (typep n 'integer) (typep m 'integer))
(cond ((and (< n 0) (< m 0)) '-)
.... )))
It's also possible to use predicates like integerp, minusp, zerop and plusp.

You can use the already functioning and tested sign definition - which is typical for the way, lispers program. The first naive solution would be:
(defun sign-for-two (n m)
(when (eql (sign n) (sign m))
(sign n))
;; (if (condition) return-value NIL)
;; is equivalent to
;; (when (condition) return-value)
Note, in common lisp it is important,
which equality test you choose:
;; only symbols - for object identity eq
;; symbols or numbers - for object identity eql
;; (in most tests the default)
;; eql for each component? also in lists equal
;; equal not only lists but also
;; arrays (vectors, strings), structures, hash-tables
;; however case-insensitive in case of strings
;; equalp
;; mathematical number equality =
;; specifically characters char=
;; case-sensitive string equality string=
In our case, eql is sufficient.
;; to avoid `(sign n)` to be evaluated twice,
;; you could store it using `let`
;; and call from then on the stored value
;; (which is less costly).
(defun sign-for-two (n m)
(let ((x (sign n)))
(when (eql x (sign m))
x)))
Or create an equality tester (default test function: #'eql)
which returns the equally tested value
and if not equal, NIL:
(defun equality-value (x y &key (test #'eql))
(when (funcall test z y) z)))
;; and apply this general solution to our case:
(defun sign-for-two (n m)
(equality-value (sign n) (sign m)))
and you can apply the equality-value function
in future for functions where you want to
return the value when tested as "equal"
and you can give the function via :test whatever equality
function other than eql is suitable for that case, like
(equality-value string1 string2 :test #'string=)

It looks like you have the right approach and just got lost in the parentheses. Each of your cond cases looks like
(and ((< n 0) '-) ((< m 0) '-))
I think you meant
((and (< n 0) (< m 0)) '-)
and the same thing for the other two cases.

Another compact way to write sign is to use the standard function signum which
returns one of -1, 0, or 1 according to whether number is negative,
zero, or positive
The code could look like:
(defun sign (n)
(when (integerp n)
(case (signum n)
(-1 '-)
(0 0)
(1 '+))))

Related

Common Lisp: Function returns function name

I am currently trying to solve problem 1 from projecteuler.net. Evaluation of this function only returns the name of the function. What am I doing wrong?
(defun nSum (n sum)
(if ( n = 0) ( sum) )
(cond ( (mod n 5) = 0) ( nSum ( - n 1) (+ sum n)) ( (mod n 3) = 0) (nSum(- n 1) (+ sum n)) (nSum (- n 1) (+ sum n))
)
)
(setq sum (nSum 100 0))
(write sum)
Errors
Evaluation of this function only returns the name of the function.
I cannot replicate this, how did you test your code, under which environment?
With SBCL, here is what evaluating the defun form prints:
; in: DEFUN NSUM
; (N = 0)
;
; caught WARNING:
; undefined variable: =
The = symbol is being used in a position where it is evaluated as a variable. If you want to call the function bound to =, that is (function =), which can be written also #'=, then you have to write (= ... ...).
; caught STYLE-WARNING:
; undefined function: N
Since you wrote (N = 0), i.e. with N as the first element of a form under normal evaluation rules, the code tries to call function N. In your case, you have no such function defined.
; (COND ((MOD N 5) = 0) (NSUM (- N 1) (+ SUM N)) ((MOD N 3) = 0)
; (NSUM (- N 1) (+ SUM N)) (NSUM (- N 1) (+ SUM N)))
; --> IF
; ==>
; (IF NSUM
; (PROGN (- N 1) (+ SUM N))
; (IF (MOD N 3)
; (PROGN = 0)
; (IF NSUM
; (PROGN (- N 1) (+ SUM N))
; (IF NSUM
; (PROGN # #)
; NIL))))
;
; caught WARNING:
; undefined variable: NSUM
You are writing cond clauses, and in that context, each clause is supposed to be a list matching (test . body), i.e. a test expression followed by the case body (possibly empty). You wrote:
(cond ( (mod n 5) = 0) ( nSum ( - n 1) (+ sum n)) ...)
In the above, you have two clauses, one which (tries to) tests whether N is divisible by 5, and the other which test if nSum is true.
; (SUM)
;
; caught STYLE-WARNING:
; undefined function: SUM
You added parentheses around SUM, which means you want to call function SUM (currently undefined). Parentheses matter in Lisp.
Fixing errors and formatting
Here is your code after fixing the previous errors and formatting it according to Lisp style rules:
(defun nSum (n sum)
(if (= n 0)
sum
(cond
((= 0 (mod n 5)) (nSum (- n 1) (+ sum n)))
((= 0 (mod n 3)) (nSum (- n 1) (+ sum n)))
(t (nSum (- n 1) (+ sum n))))))
Your code does not compute the desired function. Please read Gwang-Jin Kim's answer to see how to compute it a tail-recursive way, or below for a loop-based one.
Some additional remarks w.r.t. style:
You are not supposed to use snakeCase in Lisp, use instead dashes to separate words, known humbly as lisp-case (and apparently, also as kebab-case).
Your if and cond can be merged together. Also, be careful about negative N.
You can do (or test1 test2) when both tests lead to the same code being executed. This avoids code duplication.
Alternative implementation
Use LOOP:
(defun euler-1 (n)
(loop
for i below n
when (or (zerop (mod i 3))
(zerop (mod i 5)))
sum i))
(defun nsum (n)
(labels ((inner-nsum (m sum) ; using `labels` define local recursive function
(cond ((= m 0) sum)
((= (mod m 3) 0) (inner-nsum (- m 1) (+ m sum)))
((= (mod m 5) 0) (inner-nsum (- m 1) (+ m sum)))
(t (inner-nsum (- m 1) sum)))))
(inner-nsum (- n 1) 0))) ; call it with n decremented by 1
; to implement "below n"
(nsum 10) ;; 23 ; test successful!
(nsum 1000) ;; 233168
You should use eq for equality test (or perhaps equal; for integers it is the same), or = for comparing numbers. And there is no infix operator in Common Lisp. So ( n = 0) should be something like (eq n 0) or (= n 0) etc.

Lisp recursive square use one variables

This is Trying code
(defun f (a n)
(if (zerop n)
1
(* a (f a (- n 1)))))
(f 3) should return 27, (f 4) should return 256
I tried using two variables, but it be against the rules.
Is it possible to use only one variable using recursive?
Thanks for any ideas
I don't know CL, but I do know Clojure and other languages that use recursion.
In cases where a recursive function has 1 parameter acting as an accumulator, but is only set on the first call, the typical way around this is to wrap f in another function. There are 2 (basically the same) ways of doing this:
(defun g (a n)
(if (zerop n)
1
(* a (g a (- n 1)))))
(defun f (n)
; I'm assuming you want the initial value of "a" to be 1
(g 1 n))
Or, more succinctly:
(defun f (n)
(let (g (fn (n)
(if (zerop n)
1
(* a (g a (- n 1))))))))
; Instead of f being recursive, f calls g, which is recursive
(g 1 n))
Excuse any syntax errors.
Using an additional variable to count down would be the sane choice, but you don't need to change the contract of just one numeric argument input just for this. You can make a helper to do that:
(defun exptnn (n)
"Get the (expt n n)"
(check-type n integer)
(labels ((helper (acc count)
(if (zerop count)
acc
(helper (* acc n) (1- count)))))
(if (< n 0)
(/ 1 (helper 1 (- n)))
(helper 1 n))))
Now to solve with without any helpers just with one argument is possible since there is a solution doing that already, but I must say that is like programming in Brainf*ck without the joy!
CL-USER 15 > (defun f (n)
(labels ((g (m)
(if (zerop m)
1
(* n (g (1- m))))))
(g n)))
F
CL-USER 16 > (f 0)
1
CL-USER 17 > (f 1)
1
CL-USER 18 > (f 2)
4
CL-USER 19 > (f 3)
27
CL-USER 20 > (f 4)
256
CL-USER 21 > (loop for i below 10 collect (f i))
(1 1 4 27 256 3125 46656 823543 16777216 387420489)
This is a solution where no functions with more than one parameter are used (except for =, +, *, logand, ash; note also that logand and ash always take a constant as second parameter so they can be implemented as unary functions too).
The idea is to "hide" the two parameters needed for the obvious recursive approach in a single integer using odd/even bits.
(defun pair (n)
(if (= n 0)
0
(+ (* 3 (logand n 1))
(ash (pair (ash n -1)) 2))))
(defun pair-first (p)
(if (= p 0)
0
(+ (logand p 1)
(ash (pair-first (ash p -2)) 1))))
(defun pair-second (p)
(pair-first (ash p -1)))
(defun subsec (p)
(if (= 2 (logand p 2))
(- p 2)
(+ (logand p 1) 2 (ash (subsec (ash p -2)) 2))))
(defun pairpow (p)
(if (= (pair-second p) 1)
(pair-first p)
(* (pair-first p)
(pairpow (subsec p)))))
(defun f (n)
(pairpow (pair n)))
No reasonable real use, of course; but a funny exercise indeed.
Yes, this is possible:
(defun f (n)
(cond
((numberp n)
(f (cons n n)))
((zerop (car n))
1)
(t
(* (cdr n)
(f (cons (1- (car n))
(cdr n)))))))
The trick is that you can store any data structure (including a pair of numbers) in a single variable.
Alternatively, you can use helpers from the standard library:
(defun f (n)
(apply #'*
(loop repeat n collect n)))
But that doesn't use recursion. Or simply:
(defun f (n)
(expt n n))

"application: not a procedure" while computing binomial

I am defining a function binomial(n k) (aka Pascal's triangle) but am getting an error:
application: not a procedure;
expected a procedure that can be applied to arguments
given: 1
arguments...:
2
I don't understand the error because I thought this defined my function:
(define (binomial n k)
(cond ((or (= n 0) (= n k)) 1)
(else (+ (binomial(n) (- k 1))(binomial(- n 1) (- k 1))))))
In Scheme (and Lisps in general), parentheses are placed before a procedure application and after the final argument to the procedure. You've done this correctly in, e.g.,
(= n 0)
(= n k)
(- k 1)
(binomial(- n 1) (- k 1))
However, you've got an error in one of your arguments to one of your calls to binomial:
(define (binomial n k)
(cond ((or (= n 0) (= n k)) 1)
(else (+ (binomial(n) (- k 1))(binomial(- n 1) (- k 1))))))
***
Based on the syntax described above (n) is an application where n should evaluate to a procedure, and that procedure will be called with no arguments. Of course, n here actually evaluates to an integer, which is not a procedure, and can't be called (hence “application: not a procedure”). You probably want to remove the parentheses around n:
(binomial n (- k 1))
It's also worth pointing out that Dr. Racket should have highlighted the same portion of code that I did above. When I load your code and evaluate (binomial 2 1), I get the following results in which (n) is highlighted:
Your error is here:
binomial(n)
n is an integer, not a function. If you put parentheses around it like that, scheme tries to invoke an integer as a function, which naturally produces an error.
This is the correct code:
(define (binomial n k)
(cond ((or (= n 0) (= n k)) 1)
(else (+ (binomial n (- k 1))(binomial(- n 1) (- k 1))))))
Problem is at here:
(binomial (n) (- k 1))

Bignum overflow error after Euler #2 attempt

I've attempted to solve Euler Problem 2 with the following tail recursive functions:
(defun fib (num)
(labels ((fib-helper (num a b)
(cond ((or (zerop num)
(eql num 1))
a)
(t (fib-helper (decf num)
(+ a b)
a)))))
(fib-helper num 1 1)))
(defun sum-even-fib (max)
(labels ((helper (sum num)
(cond ((oddp num) (helper sum (decf num)))
((zerop num) sum)
(t (helper (+ sum (fib num))
(decf num))))))
(helper 0 max)))
Now, when I try to print the result using the function
(defun print-fib-sum (max dir file)
(with-open-file
(fib-sum-str
(make-pathname
:name file
:directory dir)
:direction :output)
(format fib-sum-str "~A~%" (sum-even-fib max))))
with a max value of 4000000, I get the error
("bignum overflow" "[Condition of type SYSTEM::SIMPLE-ARITHMETIC-ERROR]" nil)
from *slime-events*. Is there any other way to handle the number and print to the file?
First, a few small issues:
Use time instead of top.
Common Lisp standard does not require tail recursion optimization. While many implementation do it, not all of them optimize all cases (e.g., labels).
Your algorithm is quadratic in max because it computes the nth Fibonacci number separately for all indexes. You should make it linear instead.
You are computing the sum of even-indexed numbers, not even-valued numbers.
Now, the arithmetic error you are seeing: 4,000,000th Fibonacci number is pretty large - about 1.6^4M ~ 10^835951. Its length is about 2,776,968.
Are you sure your lisp can represent bignums this big?
So I've solved Euler #2 with the following tail recursive code:
(defun rev-sum-even-fib (max-val)
(labels ((helper (sum a b)
(cond ((oddp a)
(helper sum (+ a b) a))
((> a max-val)
sum)
(t
(helper (+ sum a) (+ a b) a)))))
(helper 0 1 0)))
Here, the algorithm is linear in max and evaluates in
(time (rev-sum-even-fib 4000000))
Real time: 3.4E-5 sec.
Run time: 0.0 sec.
Space: 0 Bytes
Where I've omitted the numerical answer for obvious reasons.
Since CL does not promise that it supports TCO (for example ABCL on the JVM does not support TCO - tail call optimization), it makes sense to write it portably as a loop:
(defun rev-sum-even-fib (max-val)
(loop for a = 1 then (+ a b) and b = 0 then a
until (> a max-val)
when (evenp a) sum a))

Lisp style question: memoization (caution: contains the solution for project euler #14)

I am just trying to learn some Lisp, so I am going through project euler problems. I found problem no. 14 interesting (so if you are planning to solve this problems stop reading now, because I pasted my solution at the bottom). With my algorithm it was so slow, but after using memoization (I copied the function from Paul Graham's "on Lisp" book) it was much more faster (around 4 to 8 seconds).
My question is about this bunch of warnings that I got:
Am I doing something wrong? Can I improve my style?
> ;; Loading file
> /euler-lisp/euler-14.lisp
> ... WARNING in COLLATZ-SERIE :
> COLLATZ-SERIE-M is neither declared
> nor bound, it will be treated as if it
> were declared SPECIAL. WARNING in
> COLLATZ-SERIE : COLLATZ-SERIE-M is
> neither declared nor bound, it will be
> treated as if it were declared
> SPECIAL. WARNING in COMPILED-FORM-314
> : COLLATZ-SERIE-M is neither declared
> nor bound, it will be treated as if it
> were declared SPECIAL. (525 837799)
> Real time: 18.821894 sec. Run time:
> 18.029127 sec. Space: 219883968 Bytes GC: 35, GC time: 4.080254 sec. Las
> siguientes variables especiales no han
> sido definidas: COLLATZ-SERIE-M 0
> errores, 0 advertencias ;; Loaded file
This is the code:
(defun collatz (n)
(if (evenp n) (/ n 2) (+ (* 3 n) 1)))
(defun memoize (fn)
(let ((cache (make-hash-table :test #'equal)))
#'(lambda (&rest args)
(multiple-value-bind (val win) (gethash args cache)
(if win
val
(setf (gethash args cache)
(apply fn args)))))))
(defun collatz-serie (n)
(cond ((= n 1) (list 1))
((evenp n) (cons n (funcall collatz-serie-m (/ n 2))))
(t (cons n (funcall collatz-serie-m (+ (* 3 n) 1))))))
(defun collatz-serie-len (n)
(length (collatz-serie n)))
(setq collatz-serie-m (memoize #'collatz-serie))
(defun gen-series-pairs (n)
(loop for i from 1 to n collect
(list (collatz-serie-len i) i)))
(defun euler-14 (&key (n 1000000))
(car (sort (gen-series-pairs n) #'(lambda (x y) (> (car x) (car y))))))
(time (print (euler-14)))
Thanks a lot, and forgive the probable errors, I am just beginning with Lisp.
Br
UPDATE:
i want to share the final code that i wrote. using custom external hash table for memoization and improving the final loop.
(defvar *cache* (make-hash-table :test #'equal))
(defun collatz (n)
(if (evenp n) (/ n 2) (+ (* 3 n) 1)))
(defun collatz-serie (n)
(cond ((= n 1) (list 1))
((evenp n) (cons n (collatz-serie (/ n 2))))
(t (cons n (collatz-serie (+ (* 3 n) 1))))))
(defun collatz-serie-new (n)
(labels ((helper (n len)
(multiple-value-bind (val stored?) (gethash n *cache*)
(if stored?
val
(setf (gethash n *cache*) (cond ((= n 1) len)
((evenp n) (+ len (helper (/ n 2) len)))
(t (+ len (helper (+ (* 3 n) 1) len)))))))))
(helper n 1)))
;; learning how to loop
(defun euler-14 (&key (n 1000000))
(loop with max = 0 and pos = 0
for i from n downto 1
when (> (collatz-serie-new i) max)
do (setf max (collatz-serie-new i)) and do (setf pos i)
finally (return (list max pos))))
It is bad style to setq an unknown name. It is assumed that you mean to create a new global special variable, then set it, but this should be made explicit by introducing these bindings first. You do this at the top level by using defvar (or defparameter or defconstant) instead, and in lexical blocks by using let, do, multiple-value-bind or similar constructs.