Lisp: How to write an if statement with multiple conditions? - lisp

I understand how to write an if statement with an individual condition. For example:
(if (> a 20))
However, after researching online, I found no resources explaining how to write an if statement with multiple conditions (for example, checking if a > 20 or a < 10). How do I write an if statement with multiple conditions in Lisp?

The if special form is the same no matter what:
(if test-expression
true-expression
false-expression)
If you want something to happen if both a is above 20 or below 10 you just do:
(if (not (<= 10 a 20)) ; same as (or (> 20 a) (< 10 a))
true-expression
false-expression)
But I get it. What if you have two expressions where one of them true should trigger, then you can use or:
(if (or (> 20 a) (< 10 a))
true-expression
false-expression)
Now and and or are macros for nexted ifs. Eg. The expression above can be done like this:
(if (> 20 a)
true-expression
(if (< 10 a)
true-expression
false-expression)))
Where true-expression is the same expression both places.

Use the OR and/or AND macros to combine conditions.
(if (or (> a 20) (< a 10))
;; do something
)

Related

LISP Sum of list items

I wrote this macro that rewrites e.g. (sum-expr (1 2 3)) as (+ 1 2 3):
(defmacro sum-expr (expr-list)
`(+ ,#expr-list))
=> SUM-EXPR
For example:
(sum-expr ((+ 1 3) (* 3 4) (- 8 4)))
=> 20
How can I define an equivalent function using defun?
As #LeonardoDagnino already mentioned it in comment:
(defun sum-expr (lst)
(apply #'+ lst))
Would be very lispy, but implementation-dependent CALL-ARGUMENTS-LIMIT limits in some implementations the length of lst to 50 as discussed e.g. here .Therefore, the solution with reduce is cleaner.
Sounds like you need to evaluate the expressions in your list, and then reduce the resulting list by the addition function.
We can evaluate lisp expressions with eval, which we can apply to each element of the input list with mapcar.
We can then use reduce on the resulting list to find the sum.
(defun sum-expr (list)
(reduce #'+ (mapcar #'eval list)))
This makes a lot of assumptions about the structure and type of your input, but for a simple problem with well-understood inputs, it should be fine.
(You may be interested in Why exactly is eval evil?)

Is there a way to get a macro to do an extra evaluation before returning its result?

I’m trying to get get my macro to do an extra evaluation of its result before returning it. Can this be done without eval?
I'm trying to solve the problem in exercise 4 below:
Define a macro nth-expr that takes an integer n and an arbitrary number of expressions, evaluates the nth expression and returns its value. This exercise is easy to solve, if you assume that the first argument is a literal integer.
4. As exercise 3, but assume that the first argument is an expression to be evaluated.
It's easy to get the macro to pick the right expression:
(defmacro nth-expr% (n &rest es)
`(nth ,n ',es))
CL-USER> (defvar i 1)
I
CL-USER> (nth-expr% (1+ i) (+ 2 3) (- 4 3) (+ 3 1))
(+ 3 1)
The expression (+ 3 1) is the one we want, but we want the macro to evaluate it to 4 before returning it.
It can of course be done with eval:
(defmacro nth-expr%% (n &rest es)
`(eval (nth ,n ',es)))
CL-USER> (nth-expr%% (1+ i) (+ 2 3) (- 4 3) (+ 3 1))
4
But is there another way?
It feels like the solution should be to put the body of nth-expr% in a helper macro and have the top level macro only contain an unquoted call to this helper:
(defmacro helper (n es)
`(nth ,n ',es))
(defmacro nth-expr (n &rest es) ; doesn't work!
(helper n es))
The idea is that the call to helper would return (+ 3 1), and this would then be the expansion of the call to nth-expr, which at run-time would evaluate to 4. It blows up, of course, because N and ES get treated like literals.
That's not that easy.
Using eval is not good, since eval does not evaluate the code in the local lexical environment.
Remember, if we allow an expression to be evaluated to determine the number of another expression to execute, then we don't know this number at macro expansion time - since the expression could be based on a value that needs to be computed - for example based on some variable:
(nth-expression
foo
(bar)
(baz))
So we might want to think about code which does that:
(case foo
(0 (bar))
(1 (baz)))
CASE is evaluating foo and then uses the result to find a clause which has the same value in its head. The consequent forms of that clause then will be evaluated.
Now we need to write code which expands the former into the latter.
This would be a very simple version:
(defmacro nth-expression (n-form &body expressions)
`(case ,n-form
,#(loop for e in expressions
and i from 0
collect `(,i ,e))))
Question: what might be drawbacks of using CASE like that?
Knuto: Rainer Joswig may be asking you to think about how the case statement works. Namely, that after evaluating the keyform (ie, the first argument), it will be compared sequentially to the key in each clause until a match is found. The comparisons could be time consuming if there are many clauses. You can discover this by carefully reading the entry for case in the Hyperspec (as he more than once has insisted I do):
The keyform or keyplace is evaluated to produce the test-key. Each of
the normal-clauses is then considered in turn.
Also note that constructing many case clauses will add to the time to expand and compile the macro at compile time.
Regarding your use of eval in nth-expr%%, you can still achieve the effect of an eval by switching to apply:
(defmacro nth-expr%% (n &rest es)
`(let ((ne (nth ,n ',es)))
(apply (car ne) (cdr ne))))
But see Plugging the Leaks at http://www.gigamonkeys.com/book/macros-defining-your-own.html about a more robust treatment.
In general, a more efficient way to process the expressions is as a simple vector, rather than a list. (The problem statement does not rule out a vector representation.) While nth and case involve searching through the expressions one-by-one, a function like aref or svref can directly index into it. Assuming a vector of expressions is passed to the macro along with an index, perhaps first requiring (coerce expressions 'simple-vector) if a list, then the result can be computed in constant time no matter how many expressions there are:
(defmacro nth-expr%%% (n es)
`(let ((ne (svref ',es ,n)))
(apply (car ne) (cdr ne))))
so that now
(defvar i 1)
(nth-expr%%% (1+ i) #((+ 2 3) (- 4 3) (+ 3 1))) -> 4

IF error in LISP

I am relatively new to Lisp and I was trying to do a linear search on LISP. But I haven't been able to do so. I am always getting an error that says that "IF has too few parameters".
(setq a '(8 6 2 3 9 5 1))
(LET (key))
(setq key (read))
(loop
(if(= (first a) (key)))
(return t)
(return NIL)
(setq a (rest a))
)
Many problems in your code:
Globally setq an undefined variable
(let (key)) alone does nothing. If you want to define a global variable, use defparameter or defvar.
You if has only a test, and no branches. The special operator if takes a condition, a then expression and an optional else expression: (if test then [else])
If you intended to have your return inside the if, your linear search would stop at the first comparison, because of (return NIL). Indeed, what you would have written would be equivalent to (return (= (first a) key)) and the loop would not even be needed in that case. Maybe you intended to use return to return a value from the if, but if is an expression an already evaluates as a value. return exits the loop (there is an implicit (block NIL ...) around the loop).
(setq a (rest a)) is like (pop a) and would indeed be the right thing to do if you did not already returned from loop at this point.
Just to be sure, be aware that = is for comparing numbers.
The beginning of your code can be written as:
(let ((a '(8 6 2 3 9 5 1))
(key (read)))
(linear-search key a)
Then, how you perform linear-search depends on what you want to learn. There are built-in for this (find, member). You can also use some with a predicate. Loop has a thereis clause. You can even try with reduce or map with a return-from. If you want to learn do or tagbody, you will have an occasion to use (pop a).

unbound identifier in module error ( palindrome number )

I'm a noob in scheme ... I am trying to make an exercise so that it will check if a number is a palindrome or not ( I know how to do it in c, c++ and java). But I keep getting this error "c: unbound identifier in module in: c". I searched wide and far for the error, and yes there are tens of topics on it, but all on complicated stuff that have nothing to do with my punny code. My question is, can somebody please explain to me what does the error actually mean and how can I avoid it ? My code so far :
#lang racket
(define (palindrome n)
(if (> 10 n) #t
(check n)
)
)
(define (check n)
(if (> n 0)
((= c (modulo n 10))
(= x (+ (* x 10) c))
(= n (/ n 10)))
(checkp )
)
)
(define (checkp k)
(if (= k n) #t
#f)
)
The error reported occurs in the check procedure. All those references to the variables called c and x will fail, what are those variables supposed to be? where do they come from? Remember: in Scheme = is used for comparing two numbers, not for assignment.
There are other problems. The last line of check is calling checkp, but you forgot to pass the parameter. Also the syntax in the if expression is wrong, you can't write more than two conditions in it (the "consequent" and the "alternative"), if you need more than two conditions you should use cond.
Please be careful with those parentheses, you must not use them to group expressions (they're not like curly braces!). In Scheme, if you surround an expression with () it means function application, and that's not what you want to do in check.
And in the checkp procedure we have the same problem: the variable n is unbound. It's just like in any other programming language: you have to make sure that the variables come from somewhere (a parameter, a local variable, a global definition, etc.), they can't simply appear out of thin air.
UPDATE
After the update, now it's clear what you wanted to do. I'm sorry to say this, but you don't have a good grasp of even the most basic concepts of the language. All along you needed to do an iteration (typically implemented via recursion), but this is reflected nowhere in your code - you'll have to grab a good book or tutorial on Sceheme, to get the basics right. This is how the code in Java or C would look like in Scheme:
(define (check k)
(let loop ((x 0) (n k))
(if (zero? n)
(= k x)
(loop (+ (* 10 x) (remainder n 10)) (quotient n 10)))))
(define (palindrome)
(display "Enter the number: ")
(if (check (read))
(display "The number is a palindrome")
(display "The number is not a palindrome")))
Use it like this:
(palindrome)
Enter the number: 12321
The number is a palindrome

Affect one element of a list

If I have a list of numbers
(setq numbers '(10 11 12))
and I want to increment, say, the third number, I can do this:
(setf (nth 2 numbers) (1+ (nth 2 numbers)))
But I don't like having to repeat the "(nth 2 numbers)". Is there some way I can write this but only have one reference to "(nth 2 numbers)"?
There's a macro for exactly that:
(incf (nth 2 numbers))
You can supply the value to add as an additional argument.
If you want a more general answer (e.g. for some other function than 1+), then you probably want to look at cl-callf.
Another option is to use gv-ref and gv-deref but that doesn't seem like a good fit for your case (it's rarely a good fit, actually).
Here's a pure emacs lisp way to do it without the double call to nth...
(defun inc-list(n lst)
(let ((nc (nthcdr n lst)))
(setcar nc (1+ (car nc)))
lst))