Can someone explain to me what this code does and how it works ?
(defun f (&optional (x nil) (y (if (atom x) nil (car x))))
(cond ((atom x) y)
((< (car x) y) (f (cdr x) y))
(t (f (cdr x) (car x)))))
A quick run through the code shows it's a function which returns the largest number given two numbers or a list of numbers. It'll return nil if given an atom and an error if one of the elements of the list is not a number.
here are some of the results I got:
CL-USER> (f '(1 2 3 4))
4
CL-USER> (f '(1 5 2 4))
5
CL-USER> (f '(1 5 2 4 7))
7
CL-USER> (f 'y)
NIL
CL-USER> (f 3 'y)
Y
A type error comes up when there is a non-numeric in the list:
CL-USER> (f '(1 x 2 4 7))
gives the following error
The value
X
is not of type
NUMBER
when binding SB-KERNEL::X
[Condition of type TYPE-ERROR]
As for how it works? The function compares numbers in a list, the first parameter, and a number, second param and returns the largest of them all. It does this by recursively comparing the first two numbers of the list returning the larger number which it compares to the rest of the list.
Related
I have to write a function in Racket using foldr that will take a list of numbers and remove list elements that are larger than any subsequent numbers.
Example: (eliminate-larger (list 1 2 3 5 4)) should produce (1 2 3 4)
I can do it without using foldr or any higher-order functions but I can't figure it out with foldr. Here's what I have:
(define (eliminate-larger lst)
(filter (lambda (z) (not(equal? z null)))
(foldr (lambda (x y)
(cons (determine-larger x (rest lst)) y)) null lst))
)
(define (determine-larger value lst)
(if (equal? (filter (lambda (x) (>= x value)) lst) lst)
value
null)
)
determine-larger will take in a value and a list and return that value if it is greater than or equal to all elements in the list. If not, it returns null. Now the eliminate-larger function is trying to go through the list and pass each value to determine-larger along with a list of every number after it. If it is a "good" value it will be returned and put in the list, if it's not a null is put in the list. Then at the end the nulls are being filtered out. My problem is getting the list of numbers that follow after the current number in the foldr function. Using "rest lst" doesn't work since it's not being done recursively like that. How do I get the rest of the numbers after x in foldr?
I really hope I'm not doing your homework for you, but here goes ...
How do I get the rest of the numbers after x in foldr?
Because you're consuming the list from the right, you can structure your accumulator such that "the rest of the numbers after x" are available as its memo argument.
(define (eliminate-larger lst)
(foldr
(lambda (member memo)
(if (andmap (lambda (n) (<= member n)) memo)
(cons member memo)
memo))
'()
lst))
(eliminate-larger (list 1 2 3 5 4)) ;; (1 2 3 4)
This is admittedly a naive solution, as you're forced to traverse the entire accumulator with each iteration, but you could easily maintain a max value, in addition to your memo, and compare against that each time through.
Following works:
(define (el lst)
(define (inner x lsti)
(if(empty? lsti) (list x)
(if(<= x (apply max lsti))
(cons x lsti)
lsti)))
(foldr inner '() lst))
(el (list 1 2 3 5 4))
Output:
'(1 2 3 4)
The cond version may be preferable:
(define (el lst)
(define (inner x lsti)
(cond
[(empty? lsti) (list x)]
[(<= x (apply max lsti)) (cons x lsti)]
[else lsti] ))
(foldr inner '() lst) )
I have two lists: (1 2 3) and (a b) and I need to create something like this (1 2 3 1 2 3). The result is a concatenation of the first list as many times as there are elements in the second. I should use some of the functions (maplist/mapcar/mapcon, etc.). This is exactly what I need, although I need to pass first list as argument:
(mapcan #'(lambda (x) (list 1 2 3)) (list 'a 'b))
;=> (1 2 3 1 2 3)
When I try to abstract it into a function, though, Allegro freezes:
(defun foo (a b)
(mapcan #'(lambda (x) a) b))
(foo (list 1 2 3) (list 'a 'b))
; <freeze>
Why doesn't this definition work?
There's already an accepted answer, but I think some more explanation about what's going wrong in the original code is in order. mapcan applies a function to each element of a list to generate a bunch of lists which are destructively concatenated together. If you destructively concatenate a list with itself, you get a circular list. E.g.,
(let ((x (list 1 2 3)))
(nconc x x))
;=> (1 2 3 1 2 3 1 2 3 ...)
Now, if you have more concatenations than one, you can't finish, because to concatenate something to the end of a list requires walking to the end of the list. So
(let ((x (list 1 2 3)))
(nconc (nconc x x) x))
; ----------- (a)
; --------------------- (b)
(a) terminates, and returns the list (1 2 3 1 2 3 1 2 3 ...), but (b) can't terminate since we can't get to the end of (1 2 3 1 2 3 ...) in order to add things to the end.
Now that leaves the question of why
(defun foo (a b)
(mapcan #'(lambda (x) a) b))
(foo (list 1 2 3) '(a b))
leads to a freeze. Since there are only two elements in (a b), this amounts to:
(let ((x (list 1 2 3)))
(nconc x x))
That should terminate and return an infinite list (1 2 3 1 2 3 1 2 3 ...). In fact, it does. The problem is that printing that list in the REPL will hang. For instance, in SBCL:
CL-USER> (let ((x (list 1 2 3)))
(nconc x x))
; <I manually stopped this, because it hung.
CL-USER> (let ((x (list 1 2 3)))
(nconc x x) ; terminates
nil) ; return nil, which is easy to print
NIL
If you set *print-circle* to true, you can see the result from the first form, though:
CL-USER> (setf *print-circle* t)
T
CL-USER> (let ((x (list 1 2 3)))
(nconc x x))
#1=(1 2 3 . #1#) ; special notation for reading and
; writing circular structures
The simplest way (i.e., fewest number of changes) to adjust your code to remove the problematic behavior is to use copy-list in the lambda function:
(defun foo (a b)
(mapcan #'(lambda (x)
(copy-list a))
b))
This also has an advantage over a (reduce 'append (mapcar ...) :from-end t) solution in that it doesn't necessarily allocate an intermediate list of results.
You could
(defun f (lst1 lst2)
(reduce #'append (mapcar (lambda (e) lst1) lst2)))
then
? (f '(1 2 3) '(a b))
(1 2 3 1 2 3)
Rule of thumb is to make sure the function supplied to mapcan (and destructive friends) creates the list or else you'll make a loop. The same applies to arguments supplied to other destructive functions. Usually it's best if the function has made them which makes it only a linear update.
This will work:
(defun foo (a b)
(mapcan #'(lambda (x) (copy-list a)) b))
Here is some alternatives:
(defun foo (a b)
;; NB! apply sets restrictions on the length of b. Stack might blow
(apply #'append (mapcar #'(lambda (x) a) b))
(defun foo (a b)
;; uses loop macro
(loop for i in b
append a))
I really don't understand why b cannot be a number? You're really using it as church numbers so I think I would have done this instead:
(defun x (list multiplier)
;; uses loop
(loop for i from 1 to multiplier
append list))
(x '(a b c) 0) ; ==> nil
(x '(a b c) 1) ; ==> (a b c)
(x '(a b c) 2) ; ==> (a b c a b c)
;; you can still do the same:
(x '(1 2 3) (length '(a b))) ; ==> (1 2 3 1 2 3)
i am trying to write a function in lisp which have 2 parameters one function F and one list L
if i place '> in place of F and list L is '(1 2 3 4 5) it will return 5 as 5 is biggest.
and if we put '< then it compares all list elements and gives the smallest one as output.
and so on.
we can even put custom written function in place of F for comparison.
i wish i could provide more sample code but i am really stuck at the start.
(DEFUN givex (F L)
(cond
(F (car L) (car (cdr L))
;after this i got stuck
)
)
another attemp to write this function
(defun best(F list)
(if (null (rest list)) (first list)
(funcall F (first List) (best (F list)))))
You are almost there, just the else clause returns the f's return value instead of the the best element:
(defun best (F list)
(let ((first (first list))
(rest (rest list)))
(if (null rest)
first
(let ((best (best f rest)))
(if (funcall F first best)
best
first)))))
Examples:
(best #'< '(1 2 3))
==> 3
(best #'> '(1 2 3))
==> 1
Note that this recursive implementation is not tail-recursive, so it is not the most efficient one. You might prefer this instead:
(defun best (f list)
(reduce (lambda (a b) (if (funcall f a b) b a)) list))
Or, better yet,
(defmacro fmax (f)
`(lambda (a b) (if (,f a b) b a)))
(reduce (fmax <) '(1 2 3))
==> 1
(reduce (fmax >) '(1 -2 3 -4) :key #'abs)
==> 1
(reduce (fmax <) '(1 -2 3 -4) :key #'abs)
==> 4
I am confused about the difference between '(()) and (cons null null) in scheme.
The code below show that b and c are completely the same thing.
(define (dup2 x)
(let ((d '(())))
(set-car! d (car x))
(set-cdr! d (cdr x))
d))
(define a '(1 2))
(define b (dup2 a))
(define c (dup2 a))
(set-car! b 2)
> c ;; --> (2 2)
However, when I used dup instead of dup2:
(define (dup x)
(let ((d (cons null null)))
(set-car! d (car x))
(set-cdr! d (cdr x))
d))
(define a '(1 2))
(define b (dup a))
(define c (dup a))
(set-car! b 2)
> c ;; --> (1 2)
Variable b and c are different. I have done some experiments, but I haven't understand yet.
The value of d in the first implementation is literal data, and is modified with undefined consequences. To highlight what's happening, consider the following code:
(define (incorrect-list-null-and-x x)
(let ((l '(()))) ; a list of the form (() . ())
(set-cdr! l (cons x (cdr l))) ; (cdr l) is (), so (cons x (cdr l)) should be (x . ()) == (x), right?
; and now l should be (() . (x . ())) == (() x), right?
l))
The expected result is that (incorrect-list-null-and-x n) should return a list of the form (() n), and it does the first time, but successive calls are still accessing the same data:
(incorrect-list-null-and-x 1) ;=> (() 1)
(incorrect-list-null-and-x 2) ;=> (() 2 1)
(incorrect-list-null-and-x 3) ;=> (() 3 2 1)
(incorrect-list-null-and-x 4) ;=> (() 4 3 2 1)
The same problem manifests itself a bit differently in your dup2. Every value returned from dup2 is actually the same pair:
(let* ((x (dup2 (cons 1 2)))
(y (dup2 (cons 3 4))))
(display x)
(display y))
outputs:
(3 . 4)(3 . 4)
because the call (dup2 (cons 3 4)) modifies the same structure that was previously returned by (dup2 (cons 1 2)).
Data literals, like '(()), are meant to be read-only, and modifying it using set-car! or set-cdr! has undefined behaviour. For predictable behaviour, use the (cons '() '()) version if you want to use set-car! or set-cdr! on it.
In particular, cons creates a new cons cell, whereas a data literal usually won't.
Still, for the purposes of implementing dup, why are you using set-car! and set-cdr! anyway? Just use cons directly:
(define (dup x)
(cons (car x) (cdr x)))
In your first code snippet you use (d '(())) which ends up binding a literal to d. You then modify the literal which is generally undefined. In your second code snippet you use (d (cons null null)) which binds d to a newly created 'cons cell' which you then modify. There is no problem modifying that.
Note: you've not defined null. Perhaps you meant '()?
I have this function:
(define (unfold f init)
(if (eq? (f init) '())
(list)
(cons (car (f init)) (unfold f (cdr (f init))))))
I want to use it to define a function that does:
(hypothetical-function '(1 2 3 4 5))
which should return:
'((1 2 3 4 5) (2 3 4 5) (3 4 5) (4 5) (5)
Okay, you want
(define (tails xs) (unfold foo xs))
and for that you need to define the appropriate foo. Now, what should foo do? It should return a pair, the first component of which becomes the car of the resulting list, and the second component of which becomes the seed for the recursive call - unless the unfolding is to stop, when foo should return an empty list. So
(define (foo xs)
(if (stop-condition)
'()
(cons car-of-result next-seed)))
Filling in the remaining details is left as an exercise to the reader.