Need help to understand LISP - lisp

I am trying to write my own maximum function (with 2 elements in list at present) but getting error while executing simple function as:
(defun max_for_vararg (list)
(if (null list)
(nil))
(if (> (car list) (cdr list))
(car list)
(cdr list)))
Error as:
? (max_for_vararg '(2 4))
> Error: The value (4) is not of the expected type REAL.
> While executing: CCL::>-2, in process listener(1).
> Type :POP to abort, :R for a list of available restarts.
I appreciate if someone can help me understand it. Error seems confusing to me as similar function like below is running fine but not returning max value.
(defun max_for_vararg (list)
(if (null list)
(nil))
(if (> (car list))
(car list)
(cdr list)))

Use cadr instead of cdr. Cdr gets you the rest of the list, which is a single element list. Thus, you have to call car on that list (car (cdr list)). Since this is a common thing to want to do, they made cadr a function that evaluates out to that.

There are several errors in you code. I'll give you some pointers on how to improve it.
You try to call a function named nil.
The first if has a consequence that does (nil), thus call nil as if it is a defined function. nil in other positions is the empty list so this might be an error unless you have made a function called nil.
The first if is dead code
As long as the result of the first if does not throw you into the debugger, the second if will run. Thus when the first if is fixed it will be redundant code. You really should try to have both a consequence and an alternative even though the standard doesn't require it.
(if test-1 ; predicate
test-1-true-expression ; consequent
test-1-false-expression) ; alternative
The second if should of course be one of those expressions and not something that happens unconditional to the first.
In the updated code > needs at least two arguments to be useful.
You can think of > as a function that tests if all the arguments are in descending order. (> 4) is T since all arguments are in descending order. If you find car, cadr and caddr cryptic you may want to try the aliases first, second, third instead. eg
(> (first list) (second list)) ; is first element greater than second element?

Related

Beginner LISP: At what stage in a Do Loop can I implement an IF condition?

I am designing a simple function (for class, so please no complete done-for-you answers) that returns the first odd integer in a list, or 'none if there are none.
I have a working code for finding the odd number:
(defun first-odd (lst)
(do ((numbers lst (cdr numbers)))
((oddp (car numbers)) (car numbers))))
but what I can't seem to figure out is where to place the IF conditional (which is required for the assignment) to produce "NONE" if the list is only even #s, or presumably NIL.
Do I make the exit point of the DO itself the IF conditional? Or does it go before/after?
I'm working on something like this (although I have a feeling it's wrong):
(defun first-odd (lst)
(do ((numbers lst (cdr numbers)))
((if (oddp (car numbers))
(car numbers)
(print 'none)))))
Or can someone advise me on 'where' to place the IF? Sorry for the truly beginner takes, but the prof didn't provide much documentation for DO and I've been scratching my head all weekend. Thanks in advance.
DO takes three arguments: the first one is the list of variables with their initial values and the subsequent values; the second is the terminating condition, i.e. when to exit the loop and the result to return; the third one is the body of the loop, and it's optional.
The second element contains an implicit if.
Your first code looks good with one exception: have you considered what happens if there are no odd elements in the list? You need then to test for the end of the list (i.e. when list is nil). Then, the result will depend on whether you exited the loop because an odd number was found, or a nil list. That's where you can use IF.

why lisp macro push only change symbol?

In many lisp implementation, push is a macro look like this:
(push new list)
;; equal to
(setf list (cons new list))
but setf cannot modify argument, like:
(defun add-item (new list)
(push new list))
does not work, because function argument is not original symbol.
why not push work like this:
(defun my-push (new list)
(setcdr list (cons (car list)
(cdr list)))
(setcar list new)
list)
Then push could work on argument of function.
Are there any reason make lisp push work this way?
I'm only newbie to emacs lisp and sicp scheme.
One problem with your destructive push function is that it doesn't work on the empty list nil. That's a bit of a "deal breaker".
Note that the push macro, while it is an imperative construct which mutates the value of a storage location which holds the head of the list, it avoids mutating the structure of that list.
It is easy to reason about list processing code which uses push and pop over a local variable; you don't have to be concerned about possible bugs caused by mutated list structure.
Remember that multiple symbols (or other values) may be pointing at that list, or at sub-lists thereof.
If push worked the way you suggest, then you could change the values of more than just the specified symbol.
Consider:
(setq l1 '(foo bar))
(setq l2 (append '(baz) l1))
If you now 'push' to l1 by manipulating the car and cdr of the cons cell that it points to, you would also modify the value of l2.
Of course there may be times when that is precisely what you want to do; however push is not the way to do it, and obviously you cannot redefine push to work that way without causing unwanted side effects in other code.
There are several types of mutation. One is the object, where you can alter the car or cdr or a cons to something different. The cons will have the same address before and after so every variable pointing to it will point to the same, but the object gets changed.
(defparameter *mutating-obj* (list 1))
(defparameter *mutating-obj2* *mutating-obj*)
(setf (cdr *mutating-obj*) '(2))
Here you mutate the object so both variables still point to the same value that has changed. When evaluating any of them you see (1 2).
Know that since we mutates objects the value can never be () in the beginning since it is not something with car and cdr that can be mutated.
With setf on a variabel you can think of variables as a address location to a value. Thus setf will mutate that location and not the value itself.
(defparameter *var1* '(1 2 3))
(defparameter *var2* *var1*)
Now we have two variables pointing to the same list. If I do this:
(push 0 *var2*)
Then *var2* has got its pointer changed so that it points to a new list starting with 0 and has the tail of the previous value. This does not change *var1* which still points the the previous value *var2* had.
When you call a function with a value the value gets bound as a new variable and doing push on it will do the same, alter that variable, never other variables that happen to point to the same value.
The common use for push is to start with an empty list and add elements to it. Setting car and cdr doesn't work for changing an empty list into a one element list with a given value. All variables pointing to nil will not have changed thus the method of using rplacd ( (setf (cdr var) ...) ) works if your data structure had a head element that is never used:
(defun make-stack ()
(list 'stack-head))
(defun push-stack (element stack)
(assert (eq (car stack) 'stack-head))
(setf (cdr stack) (cons element (cdr stack)))
stack)
(defun pop-stack (stack)
(let ((popped (cadr stack)))
(setf (cdr stack) (cddr stack))
popped))
This however doesn't work unless you specifically design it so so push really needs to alter the variable and not the value since then it works always. (except for beginners who thinks it alters values)
after google and read more code,
(like https://www.emacswiki.org/emacs/ListModification .)
I discover that lisp programer usually copy and modify the original list,
then assign it to the original list symbol.
maybe this is the style of lisp.
I am from javascript, which always modify original array,
but seldom copy it.
thank's for your answer.

How to increment each element in a list by 1 in LISP

I'm learning LISP and I am trying to write a function that adds 1 to each element inside my list. I first test for if the first element is a number or not then add 1 to the first element in the list. I then recursively call the function on the rest of the list but I get an error. Any help? Here's the function:
(defun add-1-all (L)
(cond (not (numberp (first L)) nil)
(t (+1 (first L)) (add-1-all (rest L)))))
Here are more approaches:
When dealing with lists (see Joshua's comment), use ENDP, FIRST and REST, which are preferred over NULL, CAR and CDR. They convey the intent more clearly and in the case of ENDP, check that the argument is a proper-list. Imagine you pass a dotted-list built with (cons 'a 'b), what should happen? ENDP detects that the list is not proper and signals an error.
(defun add-1-all (list)
(unless (endp list)
(cons (1+ (first list))
(add-1-all (rest list)))))
I used UNLESS for its NIL value, which some people might not like. You may want to explicitely return NIL when reaching the end of your list. In that case, stick with COND or just use IF.
Loop.
(defun add-1-all (list)
(loop for e in list collect (1+ e)))
Make it work on arrays too, not just lists.
(defun add-1-all (sequence)
(map (type-of sequence) #'1+ sequence))
The easiest way to accomplish your goal would be to use map. Map applies a function to each element of a sequence. That way one does not have to take care of details like iterating through the sequence. In the code below I use mapcar which works only on lists.
(defun add-1 (list)
(mapcar #'1+ list))
To find out about other mapping functions that CL provides run (apropos "map") and use (describe ) to find out more. Or better yet use the clhs search engine or the extended CL documentation search engine
The solution you provided is attempting to solve the problem through recursion. The general idea is to traverse the list using first/rest while building a new one with the elements incremented by one. When the list reaches the end (You can use the functions null or endp to test that the end of the list has been reached) the new list should be returned. One of the problems with your solution is that it lacks an accumulator. Also your base-case (the condition that signals to stop the recursion) is wrong.
A couple of other pointers. Use an editor that formats your code as it is difficult to read. Also CL is not a Lisp-1 so you can use list as a variable name and it won't collide with the function list. They have separate namespaces. It is also helpful to post the error message and the explain what/how your solution is trying to do. You may also find this textbook useful for learning Lisp
You could write (+ 1 (first L)) or (1+ (first L)) but you didn't write that.
Also, you should use cons to tack the result on the first element to the result of the rest of them.
Also, did you really want to drop off all the elements after the first non-number? Or did you want to assume all elements were numbers, in which case you should learn about map or mapcar, which allows you to solve the problem in 15 characters.
First of all your code is wrong if you compile it you get several errors and warnings, is important a good lisp syntax and also knowing what you are writing. If you are learning lisp I reccomend you to get a confortable environment for that like slime and quicklisp
; SLIME 2015-06-01; compiling (DEFUN ADD-1-ALL ...)
; file: /tmp/file451NPJ
; in: DEFUN ADD-1-ALL
; (1 (FIRST L))
;
; caught ERROR:
; illegal function call
; (REST L)
; --> CDR
; ==>
; L
;
; note: deleting unreachable code
; (COND (NOT (NUMBERP (FIRST L)) NIL) (T (1 (FIRST L)) (ADD-1-ALL (REST L))))
; ==>
; (IF NOT
; (PROGN (NUMBERP (FIRST L)) NIL)
; (COND (T (1 (FIRST L)) (ADD-1-ALL (REST L)))))
;
; caught WARNING:
; undefined variable: NOT
;
; compilation unit finished
; Undefined variable:
; NOT
; caught 1 ERROR condition
; caught 1 WARNING condition
; printed 1 note
Then it is a good idea to use recursion for doing this task, for recursions is important to know when to stop and the base case of your algorithm
In you case you can also use if for this two path the function will be this:
(defun add-1-all (list)
(cond
((null list) nil)
(t (cons (1+ (car list))(add-1-all (cdr list))))))
I recommend you to try doing this using a tail recursive function for better perfomance and a great learning.
Also with lisp you can use more functional style, when time comes you will learn this, like using higher order functions in this case your function is as follows:
;; functional programming higher order functions
(defun add-1-all-ho (list)
(mapcar #'1+ list))

CLISP - Reversing a simple list

I have to reverse the elements of a simple (single-dimension) list. I know there's a built-in reverse function but I can't use it for this.
Here's my attempt:
(defun LISTREVERSE (LISTR)
(cond
((< (length LISTR) 2) LISTR) ; listr is 1 atom or smaller
(t (cons (LISTREVERSE (cdr LISTR)) (car LISTR))) ; move first to the end
)
)
Output pretty close, but is wrong.
[88]> (LISTREVERSE '(0 1 2 3))
((((3) . 2) . 1) . 0)
So I tried to use append instead of cons:
(t (append (LISTREVERSE (cdr LISTR)) (car LISTR)))
But got this error:
*** - APPEND: A proper list must not end with 2
Any help?
I can give you a couple of pointers, because this looks like homework:
The base case of the recursion is when the list is empty (null), and not when there are less than two elements in the list
Consider defining a helper function with an extra parameter, an "accumulator" initialized in the empty list. For each element in the original list, cons it at the head of the accumulator. When the input list is empty, return the accumulator
As an aside note, the above solution is tail-recursive.
As a follow-up to Óscar López (and fighting the temptation to just write a different solution down):
Using both append and length makes the posted solution just about the least efficient way of reversing a list. Check out the documentation on cons and null for some better ideas on how to implement this.
Please, please indent properly.
Tail recursion really is both more efficient and reasonably simple in this case. Try it if you haven't already. labels is the form you want to use to define local recursive functions.
It may be worth your while to flip through The Little Schemer. It'll give you a better feel for recursion in general.
It's ok what you did. You only missed the composition of the result list.
Think about it: You have to append the 1-element list of the CAR to the end of the list of the reversed CDR:
(defun LISTREVERSE (LISTR)
(cons
((< (length LISTR) 2) LISTR) ; listr is 1 atom or smaller
(t (append (LISTREVERSE (cdr LISTR)) (list (car LISTR))))))
(defun listreverse (list)
(let (result)
(dolist (item list result)
(push item result))))
Don't use recursion in Common Lisp when there is a simple iterative way to reach the same goal. Common Lisp does not make any guarantees about tail recursion, and your tail recursive function invocation may not be optimized to a jump at the discretion of the compiler.
push prepends the item to the result
dolist has an optional third argument which is the value returned. It is evaluated when the loop is exited.

Get Last Element of each list

Let us say I have a list ((3 4 5) (d e f) (h i j) (5 5 5 5))
How can I get the last element of each list in such a way that the output would look like this (5 f j 5)?
Assuming this is about Common Lisp, there is a function last which returns a list containing the last item of a list. If you use this function with mapcan, which applies a given function to each element of a list and returns the concatenated results, you'll get what you want.
Note though that accessing the last element of a list is an O(N) operation, so if this isn't just homework after all, you might want to consider if you can't solve the real problem more efficiently than taking the last item of each list (maybe use another datastructure instead).
This, like most early LISPy homework problems is an exercise in thinking recursively and/or thinking in terms of induction. The way to start is to ask yourself simple questions that you can answer easily.
For example, if you had been asked to write something that gave you the first element in each list, I would thing about it this way:
Given a list of lists:
What is first-element of every list in the list '()? (easy - null)
What is first-element of every list in the list '(a)? (easy - a, or maybe an error)
What is first-element of every list in the list '((a))? (easy - (a))
What is first-element of any list in the form '(anything), where anything is a list? (easy - (first anything))
What is the first element of every list in the form '(anything morestuff)? (easy - (cons (first anything) (first-element morestuff)) )
What is first of an atom? either the atom or an error (depends on your point of view)
What is first of null? nil.
What is first of a list? (car list)
From here we can start writing code:
;; here's first, meeting questions 6-8
(define first (lambda (l)
(cond
((null? l) nil) ; Q7
((atom? l) l) ; Q6
(t (car l))))) ; Q8
;; with first we can write first-element, meeting questions 1-5
(define first-element (lambda (l)
(cond
((null? l) nil) ; Q1
((atom? l) (first l)) ; Q2
(t (cons (first (car l) (first-element (cdr l)))))))) ; Q4-5
Now this isn't your homework (intentionally). You should play with this and understand how it works. Your next goal should be to find out how this differs from your assignment and how to get there.
With respect to MAPCAR? Don't worry about it. You need to learn how to solve recursive problems first. Then you can worry about MAPCAR. What is the point of this assignment? To help you learn to think in this mode. Dang near everything in LISP/Scheme is solved by thinking this way.
The reason I went with all the questions to break it down into the parts that I'm worried about. If I'm given the task "how do I do foo on every item in a list?" I should answer the questions: How do I do handle null? How do handle an atom? How do I do handle on the first element on the list? How do I handle everything else? Once I've answered that, then I figure out how to actually do foo. How do I do foo on null? How do I do foo on an atom? How do I do foo on a list?
(defun get-last-lists (s)
(setq rt 'nil)
(loop for i from 0 to (- (length s) 1)
do (setq rt (append rt (last (nth i s)))))
(print rt))
as a beginner of lisp, i post my solution.
Write a procedure that returns the last element of a list, then learn a little about the built-in MAP (a.k.a. MAPCAR) procedure and see if any lightbulbs go off.
probably it is already solved, but I figured this out
; SELECT-FROM-INNER-LIST :: [list] -> [list]
(DEFUN SFIL (lst)
(COND ((NULL lst) NIL)
((LISTP (FIRST lst)) (APPEND (LAST (FIRST lst)) (SFIL (REST lst))))
))
Now, this works for legit list...so if you call function SFIL with correct list.... if not, it will return NIL
hopefully this will be helpful, for anyone who finds it