1
votes

I have the 2 lists, '(1 2 3 4), and '(add1 sub1 add1). They do not have same length. The first list is numbers, the second list is functions. I want to apply the functions to each of element in the number list.

'(1 2 3 4) (add1 sub1 add1) -> '(2 3 4 5) '(sub1 add1)

It look very simple, but I find I can not update the lists. Because in Scheme there is no way to update lists without hash. I can only create new lists. So every time I have to create a new list for each function in the second list. Can someone help me code this question?

2
"There is no way to update lists without hash" that is not correct, there are ways to modify a list in-place. But anyway the idiomatic way to operate on lists in Scheme is to create new lists with the result of modifications, so you're on the right track there. - Óscar López

2 Answers

2
votes

Alternatively you could use map and compose in combination. This is much easier to read and understand.

(map (compose add1 sub1 add1) '(1 2 3 4))
;; '(2 3 4 5)

(compose add1 sub1 add1) chains the functions one after another and map applies this chained/composed function on each element of the input list '(1 2 3 4).

Generalize to a function:

(define (map-functions funcs . args)
  (apply map (apply compose funcs) args))

(map-functions (list add1 sub1 add1) '(1 2 3 4)) ;; '(2 3 4 5)

compose is inbuilt but one can define it like this (% in names to not to overwrite the existing compose.

;; first a compose to compose to functions
(define (%%compose f1 f2)
  (lambda args
    (f1 (apply f2 args))))

;; then, generalize it for as many functions as one wants (as a variadic function) using `foldl`
(define (%compose . funcs)
  (foldl %%compose (car funcs) (cdr funcs)))
0
votes

You're looking for a left fold. It looks like Racket calls it foldl, which will do the job, combined with map. Something like (Untested, because I don't have Racket installed):

(define functions (list add1 sub1 add1)) ; So you have functions instead of symbols like you get when using quote
(define numbers '(1 2 3 4))
(foldl (lambda (f lst) (map f lst)) numbers functions)

Basically, for each function in that list, it maps the function against the list returned by mapping the previous function (Starting with the initial list of numbers when there is no previous).


If you're stuck with a list of symbols and can't use the (list add1 ... trick to get references to the actual functions, one approach (And I hope there are better ones) is to use eval and some quasiquoting:

(foldl (lambda (f lst) (eval `(map ,f (quote ,lst)))) '(1 2 3 4) '(add1 sub1 add1))