如何知道foldr的组合函数应该采用什么参数?

时间:2016-12-15 01:12:01

标签: scheme racket

对于内置函数foldr,我知道函数blueprint如下:

(foldr combine base alist)

combine应该包含两个参数:

  1. 折叠器消耗的项目

  2. 将foldr应用于alist的其余部分的结果

  3. 我似乎无法理解如何将#2点放在参数形式中。你是怎么做到的?

    combine不是内置函数。我必须根据要求自己编写代码。

2 个答案:

答案 0 :(得分:1)

将第二个参数视为目前的累计值。例如,如果我们要添加元素,那么acc是所有先前ele的总和,我们需要添加当前元素:

(foldr (lambda (ele acc) (+ ele acc))
       0 ; we're adding numbers, so the base is 0
       '(1 2 3 4 5))
=> 15

另一个例子 - 如果我们要复制列表,那么acc包含列表中的前一个ele(从最后一个开始并从那里返回)我们必须cons 1}}头部的当前元素:

(foldr (lambda (ele acc) (cons ele acc))
       '() ; we're creating a list, so the base is an empty list
       '(1 2 3 4 5))
=> '(1 2 3 4 5)

acc的确切性质取决于要解决的问题,但您应该能够从前面的示例中获得想法。

答案 1 :(得分:0)

将其视为到目前为止计算的结果,foldr从头到尾迭代,而foldl从头到尾迭代。如果你看一个简单的实现,它会更容易看到:

(define (foldr1 f init lst)
  (let r ((lst lst))
    (if (null? lst)
        init
        (cons (f (car lst)) (r (cdr lst))))))          

(foldr1 combine base '(1 2 3))            ; ==
(combine 1 (combine 2 (combine 3 base)))

(define (foldl1 f init lst)
  (let r ((lst lst) (acc init))
    (if (null? lst)
        acc
        (r (cdr lst) (f (car lst))))))

(foldl1 combine base '(1 2 3))            ; ==
(combine 3 (combine 2 (combine 1 base)))

另请注意,在某些实现中,顺序或参数会发生变化。 Racket和SRFI-1始终将累加器作为最后一个参数,但在R6RS中,fold-left(但不是fold-right)的参数顺序更改:

#!r6rs
(import (rnrs))

;; swap argument order 
(fold-left (lambda (acc e) (cons e acc)) '() '(1 2 3))
; ==> (3 2 1)