Why this reduce function call does not work in Common Lisp? - common-lisp

Using Common Lisp (SBCL), I can successfully evaluate in REPL:
CL-USER> (reduce #'+ '(1 2 3 4))
10
However, this fails:
> (reduce #'(lambda (e) (+ e 100)) '(1 2 3 4))
The debugger throws an error:
invalid number of arguments: 2
I was expecting an accumulating effect, so the sum would be 110.
How can I achieve the expected result? Do I need to use something else than reduce?

The reducing function must accept two arguments. Your lambda function accepts only one. Even if it worked it would add 100 to your result on each step of the additions along the list.
What you mean is specifying the initial value. The simplest hacky way is just to cons it onto your list, like
> (reduce #'+ (cons 100 '(1 2 3 4)))
110
The proper way, going by the specs, is to explicitly specify it with the :initial-value keyword parameter:
> (reduce #'+ '(1 2 3 4) :initial-value 100)
110
And if you do want to add the 100 on each reduction step,
> (reduce #'(lambda (a x) (+ 100 a x)) '(1 2 3 4))
310
You might want to add one more 100 by specifying is as the :initial-value as well.

Calling (reduce #'f '(1 2 3 4)) will compute
(f (f (f 1 2) 3) 4)
So for example
>>> (reduce #'(lambda (a b) (cons a b)) '(1 2 3 4))
(((1 . 2) . 3) . 4)
Thus, the function you pass to reduce needs to accept two arguments. This function is first called with the first two elements of the sequence. Then the function is called with result of the previous call and the next element in the sequence and so on (see [CLHS reduce]). To obtain the sum of all elements you need to call the following:
>>> (reduce #'(lambda (a b) (+ a b)) '(1 2 3 4))
10
The behavior of reduce can be altered by providing an initial value. Calling
(reduce #'f '(1 2 3 4) :initial-value 100)
will compute the following:
(f (f (f (f 100 1) 2) 3) 4)
Thus, if you want to get the desired result you can use:
>>> (reduce #'+ '(1 2 3 4) :initial-value 100)
110
To add 100 to each of the numbers and then compute the sum, you can use a combination of reduce and mapcar, which is a common pattern in functional programming:
>>> (reduce #'+ (mapcar #'(lambda (a) (+ a 100)) '(1 2 3 4)))
410

Related

Creating a function to pair the corresponding elements in 2 lists

I am learning to use scheme and practicing by creating functions from practice problems I saw in a book. This one is called zipper.
I have already made the zipper function using recursion with only cons, car, and cdr.
Now I am trying to make this same function again but also using map or fold.
The function takes in two lists and 'zips' them together:
(zip '(1 2 3) '(4 5 6))
==> '((1 4) (2 5) (3 6))
How can I do this using either map or fold?
It may become clearer if the function to be used by map is declared separately:
(define (zip1 x y)
(list x y))
(map zip1 '(1 2 3) '(4 5 6)) ; corresponding elements of 2 lists will be sent to zip1
Since zip1 is only 'list', following also works:
(map list '(1 2 3) '(4 5 6))
Output for both:
'((1 4) (2 5) (3 6))
Hence to do (zip L1 L2), one does not need to write special zip function, one can just do (map list L1 L2).
This can also be used for any number of lists, e.g. (map list L1 L2 L3 L4) which may be an advantage over custom-made zip function made for 2 lists only.
The Racket documentation for map provides the following example:
> (map (lambda (number1 number2)
(+ number1 number2))
'(1 2 3 4)
'(10 100 1000 10000))
'(11 102 1003 10004)
Notice that this is very similar to what you are trying to achieve, but instead of mapping the + function between corresponding elements in two lists, you can map a list function, as follows:
> (map (lambda (number1 number2)
(list number1 number2))
'(1 2 3 4)
'(10 100 1000 10000))
'((1 10) (2 100) (3 1000) (4 10000))
and hence, a zip function becomes:
(define (zip lst1 lst2)
(map
(lambda(elem1 elem2)
(list elem1 elem2))
lst1 lst2))

Scheme: given a list of lists and a permutation, permute

I am practicing for my programming paradigms exam and working through problem sets I come to this problem. This is the first problem after reversing and joining lists recursively, so I suppose there is an elegant recursive solution.
I am given a list of lists and a permutation. I should permute every list including a list of lists with that specified permutation.
I am given an example:
->(permute '((1 2 3) (a b c) (5 6 7)) '(1 3 2))
->((1 3 2) (5 7 6) (a c b))
I have no idea even how to start. I need to formulate the problem in recursive interpretation to be able to solve it, but I can not figure out how.
Well, let's see how we can break this problem down. We are given a list of lists, and a list of numbers, and we want to order each list according to the order specified by the list of numbers:
=>(permute '((1 2 3) (4 5 6)) '(3 2 1))
'((3 2 1) (6 5 4))
We can see that each list in the list of lists can be handled separately, their solutions are unrelated to each other. So we can have a helper permute1 that handles the case of one list, then use map to apply this function to each of the lists (with the same ordering each time):
(define (permute lists ordering)
(map (lambda (xs) (permute1 xs ordering))
lists))
(define (permute1 items ordering)
...)
Now, to calculate (permute1 '(4 5 6) '(3 2 1)), what we mean is:
The first item of the new list will be the 3rd item of items, because the first number in ordering is 3.
The rest of the items of the new list will be determined by using the rest of the numbers in the ordering.
If the ordering is the empty list, return the empty list.
This forms the base case (3), the recursive case (1), and the steps to recur deeper (2). So a sketch of our solution would look like:
(define (permute1 items ordering)
(if (empty? ordering)
'()
(let ([next-item ???])
(??? next-item
(permute1 items (rest ordering))))))
Where the ???s represent getting the item based on the first number in ordering and combining this item with the remainder of the calculation, respectively.
Here's another option, using higher-order functions. This is the idiomatic way to think about a solution in a functional language - we split the problem in sub-problems, solve each one using existing procedures and finally we compose the answer:
(define (atom? x)
(and (not (null? x))
(not (pair? x))))
(define (perm lst order)
(foldr (lambda (idx acc)
(cons (list-ref lst (sub1 idx)) acc))
'()
order))
(define (permute lst order)
(if (atom? lst)
lst
(perm (map (lambda (x) (permute x order)) lst)
order)))
We start by defining atom?, a generic predicate and perm, a helper that will reorder any given list according to the ordering specified in one of its parameters. It uses foldr to build the output list and list-ref to access elements in a list, given its 0-based indexes (that's why we subtract one from each index).
The main permute function takes care of (recursively) mapping perm on each element of an arbitrarily nested input list, so we can obtain the desired result:
(permute '((1 2 3) (a b c) (5 6 7)) '(1 3 2))
=> '((1 3 2) (5 7 6) (a c b))
I am given an example:
(permute ('(1 2 3) '(a b c) '(5 6 7)) '(1 3 2))
((1 3 2) (5 7 6) (a c b))
The syntax you've given isn't correct, and will cause an error, but it's fairly clear what you mean. You want that
(permute '((1 2 3) (a b c) (5 6 7)) '(1 3 2))
;=> ((1 3 2) (5 7 6) (a c b))
Now, it's not clear how you're indicating the permutation. Is '(1 3 2) a permutation because it has some (1-based) indices, and indicates the way to rearrange elements, or is it because it is actually a permutation of the elements of the first list of the first list? E.g., would
(permute '((x y z) (a b c) (5 6 7)) '(1 3 2))
;=> ((x z y) (5 7 6) (a c b))
work too? I'm going to assume that it would, because it will make the problem much easier.
I have no idea even how to start. I need to formulate the problem in
recursive interpretation to be able to solve it, but I can not figure
out how.
You need to write a function that can take a list of indices, and that returns a function that will perform the permutation. E.g,.
(define (make-permutation indices)
…)
such that
((make-permutation '(3 1 2)) '(a b c))
;=> (c a b)
One you have that, it sounds like your permute function is pretty simple:
(define (permute lists indices)
(let ((p (make-permutation indices)))
(p (map p lists))))
That would handle the case you've given in your example, since (map p lists) will return ((1 3 2) (a b c) (5 7 6)), and then calling p with that will return ((1 3 2) (5 7 6) (a c b)). If you need to be able to handle more deeply nested lists, you'll need to implement a recursive mapping function.
Here's my take, which seems to be shorter than the previous examples:
(define (permute lst ord)
(define ord-1 (map sub1 ord)) ; change from 1-based to 0-based indexes
(define (perm elts) ; recursive sub-procedure
(if (list? elts)
(map perm (map (curry list-ref elts) ord-1)) ; list -> recurse
elts)) ; else return unchanged
(perm lst)) ; initial call
testing
> (permute '((1 2 3) (a b c) (5 6 7)) '(1 3 2))
'((1 3 2) (5 7 6) (a c b))
> (permute '((1 (i permute did) 3) (a b (scheme cool is)) (5 6 7)) '(1 3 2))
'((1 3 (i did permute)) (5 7 6) (a (scheme is cool) b))

Processing pairs of successive elements in a list with standard mapping functions?

I have a small exercise in Lisp:
Write a function test-delta with parameters delta and lst, which will
check if the difference between successive elements in lst is smaller than
delta. Write the function in two ways:
recursively
using a mapping function
I have no problem writing that function recursively, but I don't know which mapping function I should use. All the standard mapping functions work with only one element of the list at a time. reduce cannot be used either, because I do not have some operation to use between successive elements. What function could I use here?
All standard functions are working only with one element at time.
Reduce function cannot be use either
because i do not have some operation to use between to elements.
There's already an answer by uselpa showing that you can do this with reduce, but it feels a bit awkward to me to bend reduce to this case.
It's much more natural, in my opinion, to recognize that the standard mapping functions actually let you work with multiple lists. I'll show mapcar and loop first, and then every, which I think is the real winner here. Finally, just for completeness, I've also included maplist.
mapcar
The standard mapcar can take more than one list, which means that you can take elements from two different lists at once. Of particular note, it could take a list and (rest list). E.g.,
(let ((list '(1 2 3 4 5 6)))
(mapcar 'cons
list
(rest list)))
;=> ((1 . 2) (2 . 3) (3 . 4) (4 . 5) (5 . 6))
loop
You can use loop to do the same sort of thing:
(loop
with l = '(1 2 3 4 5 6)
for a in l
for b in (rest l)
collect (cons a b))
;=> ((1 . 2) (2 . 3) (3 . 4) (4 . 5) (5 . 6))
There are some other variations on loop that you can use, but some of them have less conventient results. E.g., you could loop for (a b) on list, but then you get a (perhaps) unexpected final binding of your variables:
(loop for (a b) on '(1 2 3 4 5 6)
collect (list a b))
;=> ((1 2) (2 3) (3 4) (4 5) (5 6) (6 NIL))
This is similar to what maplist will give you.
every
I think the real winners here, though, are going to the be every, some, notevery, and notany functions. These, like mapcar can take more than one list as an argument. This means that your problem can simply be:
(let ((delta 4)
(lst '(1 2 4 7 9)))
(every (lambda (x y)
(< (abs (- x y)) delta))
lst
(rest lst)))
;=> T
(let ((delta 2)
(lst '(1 2 4 7 9)))
(every (lambda (x y)
(< (abs (- x y)) delta))
lst
(rest lst)))
;=> NIL
maplist
You could also do this with maplist, which works on successive tails of the list, which means you'd have access to each element and the one following. This has the same 6 NIL at the end that the second loop solution did, though. E.g.:
(maplist (lambda (tail)
(list (first tail)
(second tail)))
'(1 2 3 4 5 6))
;=> ((1 2) (2 3) (3 4) (4 5) (5 6) (6 NIL))
reduce can be used:
(defun testdelta (delta lst)
(reduce
(lambda (r e)
(if (< (abs (- r e)) delta)
e
(return-from testdelta nil)))
lst)
t)
or, without return-from (but possibly slower):
(defun testdelta (delta lst)
(and
(reduce
(lambda (r e)
(and r (if (< (abs (- r e)) delta) e nil)))
lst)
t))

Common Lisp: concatenate multiple values into vector

I need a function that concatenates multiple values into (simple) vector, similar to (concatenate ). However, unlike concatenate, it should be able to handle arguments that are not vectors or sequences.
I.e. it should work like this:
(concat #(1 2) 3) => #(1 2 3)
(concat 1 2 3) => #(1 2 3)
(concat 1 #(2 3 4)) => #(1 2 3 4)
(concat #(1 2) 2 #(3 4 5)) => #(1 2 3 4 5)
How can I do this? I think I've forgotten some trivial lisp construct that makes it possible.
As far as I can tell, concatenate can't do it. and I'm not quite sure how to use make it with macro (there's ,# consturct that inserts list into resulting lisp form, but but I'm not quite sure how to distinguish between non-sequences and sequences in this case).
The reduce approach in the other reply is quadratic in time.
Here is a linear solution:
(defun my-concatenate (type &rest args)
(apply #'concatenate type
(mapcar (lambda (a) (if (typep a 'sequence) a (list a)))
args)))
Since we can compute the length of the sequence, we can allocate the result sequence and then copy the elements into it.
(defun concat (type &rest items)
(let* ((len (loop for e in items
if (typep e 'sequence)
sum (length e)
else sum 1))
(seq (make-sequence type len)))
(loop with pos = 0
for e in items
if (typep e 'sequence)
do (progn
(setf (subseq seq pos) e)
(incf pos (length e)))
else
do (progn
(setf (elt seq pos) e)
(incf pos)))
seq))
CL-USER 17 > (concat 'string "abc" #\1 "def" #\2)
"abc1def2"
Above works well for vectors. A version for lists is left as an exercise.
defun my-concatenate (type &rest vectors)
(reduce (lambda (a b)
(concatenate
type
(if (typep a 'sequence) a (list a))
(if (typep b 'sequence) b (list b))))
vectors))
You can use reduce with a little modification of #'concatenate on your arguments. If one of the arguments is not a sequence, just transform it into a list (concatenate works even with mixed arguments of simple-vectors and lists).
CL-USER> (my-concatenate 'list #(1 2 3) 3 #(3 5))
(1 2 3 3 3 5)
CL-USER> (my-concatenate 'simple-vector #(1 2 3) 3 #(3 5))
#(1 2 3 3 3 5)
CL-USER> (my-concatenate 'simple-vector 1 #(2 3) (list 4 5))
#(1 2 3 4 5)
EDIT: well, you should probably accept the other answer.

A list of functions

Is there a way to make a list that holds functions? What I'm trying to do is, make a list of some arithmetic operators (+ - * /) so I can easily manipulate their order and apply them to a list of numbers.
So, if I have that list, I'd use it like this:
(apply (map (lambda (x)
x)
'(+ - * /))
'(1 2 3 4))
I'm a novice programmer, so if there's a better way to do such operation, your advice is much appreciated.
Lists are made with the function LIST.
(list 1 2 3)
(list + - * /)
Applying a list of symbols makes no sense:
(apply (map (lambda (x) x) '(+ - * /)) '(1 2 3 4))
Would be (applying a list of functions still makes no sense):
(apply (map (lambda (x) x) (list + - * /)) '(1 2 3 4))
Simplified (still wrong):
(apply (list + - * /) '(1 2 3 4))
But, maybe you wanted this:
(map (lambda (f)
(apply f '(1 2 3 4)))
(list + - * /))
In Common Lisp:
(mapcar #'(lambda (f)
(apply f '(1 2 3 4)))
(list #'+ #'- #'* #'/))
Returns:
(10 -8 24 1/24)
I'm surprised no one has mentioned quasiquotation. :-) In Scheme, you could say:
`(,+ ,- ,* ,/)
or in Common Lisp:
`(,#'+ ,#'- ,#'* ,#'/)
In some cases, especially involving complex lists, quasiquotation makes the code much simpler to read than the corresponding list version.

Resources