0

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

4

5 回答 5

2

数据转换方法:

   (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))))

测试(在 MIT 方案中):

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

你能把它简化一下,这样就没有单独的步骤#3了吗?


我们可以在这里进一步分离出不同的点点滴滴,如

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

然后,

(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)
于 2014-03-13T11:14:00.817 回答
1

干得好:

(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)

诀窍是使用for/list(或for*/list在嵌套fors 的情况下) ,它会自动append为你做。另外,请注意,您可以只遍历列表,无需使用索引。

要获得“反过来”的结果,请反转 L1 和 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)
于 2014-03-13T10:26:34.083 回答
1
(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)

与 Will 和 Procras 一起讨论这个问题。如果您要使用方案,不妨使用惯用方案。

使用 for 构建列表对我来说有点奇怪。(列表推导更适合) For 通常用于引发顺序副作用。这和 RSR5 没有定义 for/list 或 for*/list。

Flatmap 是一种相当常见的功能范例,您可以使用 append 而不是 cons 来构建列表以避免嵌套和空子列表

于 2014-03-13T16:09:24.253 回答
1

在方案中,不建议使用 set 之类的函数!或附加!。因为它会导致数据改变或变量,而不是函数式编程风格。

应该是这样的:

(定义(添加一个列表 val lst)
  (if (null?lst) '()
    (缺点 (list val (car lst)) (add-one-list val (cdr lst)))))

(定义(添加列表 lst0 lst1)
  (如果 (null?lst0) '()
    (追加(添加一个列表(汽车 lst0)lst1)
            (添加列表 (cdr lst0) lst1))))

首先了解函数add-one-list,它递归地调用自己,每次将lst的val和first元素构建到一个列表中,并将其作为最终答案进行CONS/累加。

add-list 功能就像 add-one-list 一样。

于 2014-03-13T10:36:03.530 回答
0

它不起作用,因为像append这样的函数不会改变容器。你可以用一个变异函数来解决你的问题,比如append!. 通常变异的函数!在他们的名字中都有一个,比如set!etc。

但是可以在不进行突变的情况下实现这一目标。您必须更改算法才能将结果发送到下一次迭代。像这样:

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

如您所见,当调用循环时,结果将是:

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

按照这个逻辑,您应该能够更改您的算法以使用此方法而不是for循环。您必须传递更多参数才能知道何时必须退出和返回result

今天晚些时候我会尝试添加一个更完整的答案。

append!这是我刚刚写的一个实现:

(define (append! lst1 lst2)
  (if (null? (cdr lst1))
    (set-cdr! lst1 lst2)
    (append! (cdr lst1) lst2)))
于 2014-03-13T09:59:02.770 回答