user77292
user77292

Reputation: 3

how to write scheme function that takes two lists and return one list like this

how to implement this function

if get two list (a b c), (d e)

and return list (a+d b+d c+d a+e b+e c+e)

list element is all integer and result list's element order is free

I tried this like

(define (addlist L1 L2)
  (define l1 (length L1))
  (define l2 (length L2))
  (let ((result '()))
     (for ((i (in-range l1)))
        (for ((j (in-range l2)))
           (append result (list (+ (list-ref L1 i) (list-ref L2 j))))))))

but it return error because result is '()

I don't know how to solve this problem please help me

Upvotes: 0

Views: 2371

Answers (5)

Will Ness
Will Ness

Reputation: 71119

A data-transformational approach:

   (a b c ...) (x y ...) 
1.  ==>  ( ((a x) (b x) (c x) ...)  ((a y) (b y) (c y) ...) ...)
2.  ==>  (  (a x) (b x) (c x) ...    (a y) (b y) (c y) ...  ...)
3.  ==>  (  (a+x) (b+x) ... )

(define (addlist L1 L2)
    (map (lambda (r) (apply + r))    ; 3. sum the pairs up
         (reduce append '()          ; 2. concatenate the lists
            (map (lambda (e2)        ; 1. pair-up the elements
                    (map (lambda (e1) 
                            (list e1 e2))  ; combine two elements with `list`
                         L1))
                 L2))))

testing (in MIT-Scheme):

(addlist '(1 2 3) '(10 20))
;Value 23: (11 12 13 21 22 23)

Can you simplify this so there's no separate step #3?


We can further separate out the different bits and pieces in play here, as

(define (bind L f) (join (map f L)))
(define (join L) (reduce append '() L))
(define yield list)

then,

(bind '(1 2 3) (lambda (x) (bind '(10 20) (lambda (y) (yield (+ x y))))))
;Value 13: (11 21 12 22 13 23)

(bind '(10 20) (lambda (x) (bind '(1 2 3) (lambda (y) (yield (+ x y))))))
;Value 14: (11 12 13 21 22 23)

Upvotes: 2

WorBlux
WorBlux

Reputation: 1413

(define (addlist L1 L2)
 (flatmap (lambda (x) (map (lambda (y) (+ x y)) L1)) L2))

(define (flatmap f L)
 (if (null? L)
     '()
     (append (f (car L)) (flatmap f (cdr L))))) 

1 ]=> (addlist '(1 2 3) '(10 20))

;Value 2: (11 12 13 21 22 23)

Going with Will and Procras on this one. If you're going to use scheme, might as well use idiomatic scheme.

Using for to build a list is a bit weird to me. (list comprehensions would fit better) For is usually used to induce sequential side effects. That and RSR5 does not define a for/list or for*/list.

Flatmap is a fairly common functional paradigm where you use append instead of cons to build a list to avoid nested and empty sublists

Upvotes: 1

liuyang1
liuyang1

Reputation: 1725

In scheme, it's not recommended using function like set! or append!. because it cause data changed or Variable, not as Funcitonal Programming Style.

should like this:

(define (add-one-list val lst)
  (if (null? lst) '()
    (cons (list val (car lst)) (add-one-list val (cdr lst)))))

(define (add-list lst0 lst1)
  (if (null? lst0) '()
    (append (add-one-list (car lst0) lst1)
            (add-list (cdr lst0) lst1))))

first understanding function add-one-list, it recursively call itself, and every time build val and fist element of lst to a list, and CONS/accumulate it as final answer.

add-list function just like add-one-list.

Upvotes: 1

uselpa
uselpa

Reputation: 18937

Here you go:

(define (addlist L1 L2)
  (for*/list ((i (in-list L1)) (j (in-list L2)))
    (+ i j)))

> (addlist '(1 2 3) '(10 20))
'(11 21 12 22 13 23)

The trick is to use for/list (or for*/list in case of nested fors) , which will automatically do the append for you. Also, note that you can just iterate over the lists, no need to work with indexes.

To get the result "the other way round", invert L1 and L2:

(define (addlist L1 L2)
  (for*/list ((i (in-list L2)) (j (in-list L1)))
    (+ i j)))

> (addlist '(1 2 3) '(10 20))
'(11 12 13 21 22 23)

Upvotes: 1

Loïc Faure-Lacroix
Loïc Faure-Lacroix

Reputation: 13610

It doesn't work because functions like append don't mutate the containers. You could fix your problem with a mutating function like append!. Usually functions that mutate have a ! in their name like set! etc.

But it's possible to achieve that without doing mutation. You'd have to change your algorithm to send the result to your next iteration. Like this:

(let loop ((result '()))
   (loop (append result '(1)))

As you can see, when loop will get called, result will be:

'()
'(1)
'(1 1)
'(1 1 1)
....

Following this logic you should be able to change your algorithm to use this method instead of for loop. You'll have to pass some more parameters to know when you have to exit and return result.

I'll try to add a more complete answer later today.

Here's an implementation of append! I just wrote:

(define (append! lst1 lst2)
  (if (null? (cdr lst1))
    (set-cdr! lst1 lst2)
    (append! (cdr lst1) lst2)))

Upvotes: 0

Related Questions