I am trying to learn how lisp works. Below is a part of a insertion sort algorithm and I don't understand what it is doing as a whole. I kind of understand what predicate list is but not sure what it is checking. Could someone explain?
(defun span (predicate list)
(let ((tail (member-if-not predicate list)))
(values (ldiff list tail) tail)))
(member-if-not p l) returns a tail of l beginning with the first element for which p is false. So (member-if-not #'evenp '(2 3 4)) is (3 4) (and this is eq to the cdr of the original list in this case).
If l2 is a tail of l1 then (ldiff l1 l2) returns a list of the elements of l1 which precede it.
So
(let ((l '(2 3 4)))
(let ((tail (member-if-not #'evenp l)))
(values (ldiff l tail) tail)))
will return (2) and (3 4) (and the second value will be the cdr of the original list).
Related
I have a function that can produce a list of n-element sublists from a list of elements but I am stuck in filtering out elements that are just permutations of each other. For example, f(A,B) -> ((A, B) (B,A)) is what I get but I just want ((A,B)) since (B,A) is a permutation. Is there a lisp function for this? I don't need the whole answer but a clue would be appreciated, note that A,B need not be atoms but can be string literals and even lists themselves.
I am doing this
(let (newlist '())
(loop :for x in l1 :do
(loop :for y in l2 :do
(push (list x y) newlist)))
... and I have another function that filters out these duplicates but it is clunky and probs won't scale for large inputs.
One interesting function is the (destructive) pushnew which pushes an element to a list only if it is not already existent in the set (list).
(defun pair-comb (l1 l2 &key (test #'eql) (key #'identity))
(let ((result '()))
(loop for x in l1 do
(loop for y in l2 do
(pushnew (list x y) result :test test :key key))
finally (return result))))
When we make the comparison between the elements in a way that it is order-agnostic, we would have the perfect function for us to collect different lists while ruling out the permutations of any of the already collected lists.
This can be done by #'sort-ing each list and compare by #'equalp or whatever equality function.
(pair-comb '(1 2 3) '(1 2 3 4 5) :test #'equalp :key (lambda (x) (sort x #'<)))
;;=> ((3 5) (3 4) (3 3) (2 5) (2 4) (2 3) (2 2) (1 5) (1 4) (1 3) (1 2) (1 1))
;; well, actually in this case #'eql would do it.
;; when using non-numeric elements, the `#'<` in sort has to be changed!
I am attempting to write a function that calls a list recursively and reverses its order. However I need to make the function operate every other recursive level and I am attempting to pass boolean arguments to use as a flag. I am very new to Lisp and keep getting an Undefined function B error.
(defun revList (L b)
(cond ((null L) nil)
((b T)
(append (revList (cdr L nil))
(list (car L))))
((b nil)
(append (revList (cdr L T))
(list (car L))))))
(print (revlist '(1 (2 3) (4 (5 6)) (7 (8 (9 10)))) t))
The first problem, and the reason for the reported error message Undefined function B is that some test forms in the cond form are attempting to call a function b which has not been defined. In a cond form the test forms are evaluated, and the result is used to determine which branch should be used. When (b T) or (b nil) are evaluated, it is expected that b is a function or macro. Instead you should use an expression which evaluates to either a true value or nil here.
There is another problem of misplaced parentheses around a couple of calls to cdr: (cdr L nil) and (cdr L T).
Once these problems are fixed, the code looks like this:
(defun revList (L b)
(cond ((null L) nil)
(b
(append (revList (cdr L) nil)
(list (car L))))
(t
(append (revList (cdr L) t)
(list (car L))))))
I'm going to rewrite the above function using some better names to make things a bit more clear. Note that the idiomatic way to introduce an else clause into a cond form is to use t as the test form in the final clause:
(defun rev-helper-1 (xs reverse-p)
(cond ((null xs) nil)
(reverse-p
(append (rev-helper-1 (cdr xs) nil)
(list (car xs))))
(t
(append (rev-helper-1 (cdr xs) t)
(list (car xs))))))
This code compiles and runs, but probably does not do what is expected. When reverse-p is true the code does exactly the same thing as when it is false, except that the sense of reverse-p is flipped. So the code always reverses its input:
CL-USER> (rev-helper-1 '(1 2 3 4) t)
(4 3 2 1)
CL-USER> (rev-helper-1 '(1 2 3 4) nil)
(4 3 2 1)
Further, this code does not descend into nested lists:
CL-USER> (rev-helper-1 '(1 2 3 4 (a b c d (5 6 7 8))) nil)
((A B C D (5 6 7 8)) 4 3 2 1)
It isn't entirely clear from the OP post whether the desired goal is to reverse list elements on alternate recursive calls, or to reverse list elements in alternate levels of nesting. I suspect that the second goal is the correct one.
Reversing on Alternate Recursive Calls
To reverse list elements on alternating recursive calls, the code needs to cons the first element of the list back onto the front of the "reversed" remainder of the list whenever it is in a non-reversing call. In this way, every other element will be moved to the back of the list, and those moved to the back will be in reverse order in the final list.
(defun rev-helper-2 (xs reverse-p)
(cond ((null xs) nil)
(reverse-p
(append (rev-helper-2 (cdr xs) nil)
(list (car xs))))
(t
(cons (car xs)
(rev-helper-2 (cdr xs) t)))))
CL-USER> (rev-helper-2 '(1 2 3 4) t)
(2 4 3 1)
Reversing in Alternate Levels of Nesting
To reverse in alternate levels of nesting, the code needs distinguish between atoms and lists in the input.
If the first element of a list is an atom, and if the current level is a reversing level, then the first element is wrapped in a list and appended to the result of reversing the rest of the level. Otherwise, if the first element is an atom, and the current level is not a reversing level, then the first element is consed onto the front of "reversing" the rest of the level. In this second case "reversing" the rest of the level will not change the ordering of elements at this level, because reverse-p will be false for non-reversing levels; but the code still needs to walk over the list to see if any elements at this level are lists which require further processing.
Otherwise, the first element is a list. If the current level is a reversing level, then the first element must be "reversed", i.e., processed by the reversing function, then wrapped in a list and appended to the end of reversing the rest of the list. Otherwise the current level is not a reversing level, so the first element must be processed by the reversing function and consed onto the front of "reversing" the rest of the list.
(defun rev-helper-3 (xs reverse-p)
(cond ((null xs) nil)
((atom (car xs))
(if reverse-p
(append (rev-helper-3 (cdr xs) t)
(list (car xs)))
(cons (car xs)
(rev-helper-3 (cdr xs) nil))))
(reverse-p
(append (rev-helper-3 (cdr xs) t)
(list (rev-helper-3 (car xs) nil))))
(t
(cons (rev-helper-3 (car xs) t)
(rev-helper-3 (cdr xs) nil)))))
Using a let form to bind the results of (car xs) and (cdr xs) to a couple of descriptive identifiers reduces the number of calls to car and cdr and makes this a bit easier to read:
(defun rev-helper-4 (xs reverse-p)
(if (null xs) nil
(let ((first (car xs))
(rest (cdr xs)))
(cond ((atom first)
(if reverse-p
(append (rev-helper-4 rest t)
(list first))
(cons first
(rev-helper-4 rest nil))))
(reverse-p
(append (rev-helper-4 rest t)
(list (rev-helper-4 first nil))))
(t
(cons (rev-helper-4 first t)
(rev-helper-4 rest nil)))))))
Let's write a convenience function to make it nicer to call rev-helper-4:
(defun rev-alt (xss)
(rev-helper-4 xss t))
CL-USER> (rev-alt '(1 2 3 4))
(4 3 2 1)
CL-USER> (rev-alt '(1 2 3 4 (a b c d)))
((A B C D) 4 3 2 1)
CL-USER> (rev-alt '(1 2 3 4 (a b c d (5 6 7 8))))
((A B C D (8 7 6 5)) 4 3 2 1)
CL-USER> (rev-alt '(1 (2 3) (4 (5 6)) (7 (8 (9 10)))))
((7 ((9 10) 8)) (4 (6 5)) (2 3) 1)
Hello I am looking forward to convert my existing function:
(defun checkMember (L A)
(cond
((NULL L) nil)
( (and (atom (car L)) (equal (car L) A)) T )
(T (checkMember (cdr L) A))))
To use map functions, but i honestly cant understand exactly how map functions work, could you maybe advice me how this func's work?
this is my atempt:
(defun checkMem (L A)
(cond
((NULL L) nil)
( (and (atom (car L)) (equal (car L) (car A))) T )
(T (mapcar #'checkMem (cdr L) A))))
A mapping function is not appropriate here because the task involves searching the list to determine whether it contains a matching item. This is not mapping.
Mapping means passing each element through some function (and usually collecting the return values in some way). Sure, we can abuse mapping into solving the problem somehow.
But may I instead suggest that this is a reduce problem rather than a mapping problem? Reducing means processing all the elements of a list in order to produce a single value which summarizes that list.
Warm up: use reduce to add elements together:
(reduce #'+ '(1 2 3)) -> 6
In our case, we want to reduce the list differently: to a single value which is T or NIL based on whether the list contains some item.
Solution:
(defun is-member (list item)
(reduce (lambda (found next-one) (or found (eql next-one item)))
list :initial-value nil))
;; tests:
(is-member nil nil) -> NIL
(is-member nil 42) -> NIL
(is-member '(1) 1) -> T
(is-member '(1) 2) -> NIL
(is-member '(t t) 1) -> NIL ;; check for accumulator/item mixup
(is-member '(1 2) 2) -> T
(is-member '(1 2) 3) -> NIL
...
A common pattern in using a (left-associative) reduce function is to treat the left argument in each reduction as an accumulated value that is being "threaded" through the reduce. When we do a simple reduce with + to add numbers, we don't think about this, but the left argument of the function used for the reduction is always the partial sum. The partial sum is initialized to zero because reduce first calls the + function with no arguments, which is possible: (+) is zero in Lisp.
Concretely, what happens in (reduce #'+ '(1 2 3)) is this:
first, reduce calls (+) which returns 0.
then, reduce calls (+ 0 1), which produces the partial sum 1.
next, reduce calls (+ 1 2), using the previous partial sum as the left argument, and the next element as the right argument. This returns 3, of course.
finally, reduce calls (+ 3 3), resulting in 6.
In our case, the accumulated value we are "threading" through the reduction is not a partial sum, but a boolean value. This boolean becomes the left argument which is called found inside the reducing function. We explicitly specify the initial value using :initial-value nil, because our lambda function does not support being called with no arguments. On each call to our lambda, we short-circuit: if found is true, it means that a previous reduction has already decided that the list contains the item, and we just return true. Otherwise, we check the right argument: the next item from the list. If it is equal to item, then we return T, otherwise NIL. And this T or NIL then becomes the found value in the next call. Once we return T, this value will "domino" through the rest of the reduction, resulting in a T return out of reduce.
If you insist on using mapping, you can do something like: map each element to a list which is empty if the element doesn't match the item, otherwise nonempty. Do the mapping in such a way that the lists are catenated together. If the resulting list is nonempty, then the original list must have contained one or more matches for the item:
(defun is-member (list item)
(if (mapcan (lambda (elem)
(if (eq elem item) (list elem))) list)
t))
This approach performs lots of wasteful allocations if the list contains many occurrences of the item.
(The reduce approach is also wasteful because it keeps processing the list after it is obvious that the return value will be T.)
What about this:
(defun checkMember (L a)
(car (mapcan #'(lambda (e)
(and (equal a e) (list T)))
L)))
Note: it does not recurse into list elements, but the original function did not either.
(defun memb (item list)
(map nil
(lambda (element)
(when (eql item element)
(return-from memb t)))
list))
Try this,
Recursive version:
(defun checkmember (l a)
(let ((temp nil))
(cond ((null l) nil) ((find a l) (setf temp (or temp t)))
(t
(mapcar #'(lambda (x) (cond ((listp x)(setf temp (or temp (checkmember x a))))))
l)))
temp))
Usage: (checkmember '(1 (2 5) 3) 20) => NIL
(checkmember '(1 (2 5) 3) 2) => T
(checkmember '(1 2 3) 2) => T
(checkmember '((((((((1)))))))) 1) = T
This is trivial implement of course, but I feel there is certainly something built in to Racket that does this. Am I correct in that intuition, and if so, what is the function?
Strangely, there isn't a built-in procedure in Racket for finding the 0-based index of an element in a list (the opposite procedure does exist, it's called list-ref). However, it's not hard to implement efficiently:
(define (index-of lst ele)
(let loop ((lst lst)
(idx 0))
(cond ((empty? lst) #f)
((equal? (first lst) ele) idx)
(else (loop (rest lst) (add1 idx))))))
But there is a similar procedure in srfi/1, it's called list-index and you can get the desired effect by passing the right parameters:
(require srfi/1)
(list-index (curry equal? 3) '(1 2 3 4 5))
=> 2
(list-index (curry equal? 6) '(1 2 3 4 5))
=> #f
UPDATE
As of Racket 6.7, index-of is now part of the standard library. Enjoy!
Here's a very simple implementation:
(define (index-of l x)
(for/or ([y l] [i (in-naturals)] #:when (equal? x y)) i))
And yes, something like this should be added to the standard library, but it's just a little tricky to do so nobody got there yet.
Note, however, that it's a feature that is very rarely useful -- since lists are usually taken as a sequence that is deconstructed using only the first/rest idiom rather than directly accessing elements. More than that, if you have a use for it and you're a newbie, then my first guess will be that you're misusing lists. Given that, the addition of such a function is likely to trip such newbies by making it more accessible. (But it will still be added, eventually.)
One can also use a built-in function 'member' which gives a sublist starting with the required item or #f if item does not exist in the list. Following compares the lengths of original list and the sublist returned by member:
(define (indexof n l)
(define sl (member n l))
(if sl
(- (length l)
(length sl))
#f))
For many situations, one may want indexes of all occurrences of item in the list. One can get a list of all indexes as follows:
(define (indexes_of1 x l)
(let loop ((l l)
(ol '())
(idx 0))
(cond
[(empty? l) (reverse ol)]
[(equal? (first l) x)
(loop (rest l)
(cons idx ol)
(add1 idx))]
[else
(loop (rest l)
ol
(add1 idx))])))
For/list can also be used for this:
(define (indexes_of2 x l)
(for/list ((i l)
(n (in-naturals))
#:when (equal? i x))
n))
Testing:
(indexes_of1 'a '(a b c a d e a f g))
(indexes_of2 'a '(a b c a d e a f g))
Output:
'(0 3 6)
'(0 3 6)
I have the following filter function that filters out a list, x, that doesn't satisfy the function f.
For example, I call (filter 'evenp '(0 1 2 3)) and get back (NIL 1 NIL 3). But this is exactly my problem. How do I make it so that I just get back (1 3) ?
(defun filter (f x)
(setq h (mapcar #'(lambda (x1)
(funcall f x1))
x))
(mapcar #'(lambda (a b)
(cond ((null a) b)))
h x))
i.e. the problem is right here: (lambda (a b) (cond ( (null a) b) ) ) In my cond I don't have a t , or else statement, so shouldn't it just stop right there and not return nil ? How do I make it "return" nothing, not even nil, if the (cond ( (null a) b) ) isn't satisfied?
Much appreciated. :)
Based on this question it would be:
(remove-if #'evenp '(0 1 2 3))
Ignoring the other questions raised by this post, I'll say that mapcar will always return something for each thing it's mapping over, so you can't use another mapcar to clean up the NILs there. This is what mapcar does -- it walks over the item (or items, if mapping on multiple lists, as your second attempted mapcar does) and collects the result of calling some function on those arguments.
Instead, in this situation, if you had to use mapcar for some reason, and didn't want the NILs, you could use the remove function, i.e. (remove nil (mapcar ...))
Since #stark's answer is posted above, I'll say that the remove-if function there is essentially what you're trying to implement here. (That's where the question of whether or not this is for homework becomes most relevant.)
To answer the more general question of how to splice an arbitrary number of items (including none at all) into the result, mapcan (which is semantically mapcar + append) is useful for that:
(defun filter (f xs)
(mapcan (lambda (x)
(if (funcall f x)
(list x)
nil))
xs))
mapcan is also useful when you want to map an item to multiple results:
(defun multi-numbers (xs)
(mapcan (lambda (x) (list x (+ x x) (* x x))) xs))
(multi-numbers (list 1 2 3))
;=> (1 2 1 2 4 4 3 6 9)