我刚刚接过约翰休斯的文章Why Functional Programming Matters,我正试图继续使用Scheme。
他定义的第一个高阶函数是reduce,我在Scheme中定义如下:
(define u-reduce
(lambda (ff init lst)
(if (null? lst)
init
(ff (car lst) (u-reduce ff init (cdr lst))))))
我可以使用此功能在文章中重新创建reduce
的一些应用程序,但是在从reduce
移动到map
之后,事情就会分崩离析。
激励示例是doubleall = reduce doubleandcons nil
,其中doubleandcons num list = cons (2*num) list
。
我不知道如何将其转化为计划。我可以看到目标结果可以用:
(define doubleandcons
(lambda (lst)
(if (null? lst)
'()
(cons (* 2 (car lst)) (doubleandcons (cdr lst))))))
(doubleandcons '(1 2 3))
> (2 4 6)
然而,无法看到要传递给reduce
的内容以使其加倍列表的每个元素 - 也许是因为我继续跳转到map
的版本(请参阅下面的u-map
)作为解决问题的方法。
我可以看到init
= '()
,但没有传递到ff
地方以使u-reduce
表现得像u-map
的函数。
(define u-map
(lambda (ff lst)
(if (null? lst)
'()
(cons (ff (car lst)) (u-map ff (cdr lst))))))
(u-map (lambda (x) (* 2 x)) '(1 2 3))
> (2 4 6)
这可能吗?或者也许我错过了这一点?
答案 0 :(得分:3)
Common Lisp reduce
是一般fold
。在Scheme中,您有fold-right
按顺序执行元素。你的u-reduce
就像右边的折叠一样,它的参数顺序相同。因此,以下内容应适用于R6RS / R7RS:
(define (my-map fun lst)
(fold-right (lambda (x a) (cons (fun x) a)) '() lst))
正如您所看到的,我正在使用{匿名函数中的传递函数fold-right
来执行cons
。
在Scheme和Racket的其他版本中,使用SRFI-1: List library可以获得相同的行为,许多实现都支持它,所以请查看文档中如何导入/要求它。
答案 1 :(得分:2)
您应该将reduce
定义为显式懒惰,因为该文章是关于懒惰的重要性和实用性。
通常的reduce
是一个(右)折叠,即一个变形(参见Haskell的foldr
),但让我们定义paramorphism的一般性:
(define (para f z lst)
(if (null? lst)
z
(f lst (car lst) ;; usually, f (cdr lst) (car lst) ...
(lambda () (para f z (cdr lst))))))
(另见this)。我们这样使用它:
;; doubleall = reduce doubleandcons nil
;; where doubleandcons num rest = cons (2*num) rest
(define (doubleall lst)
(para doubleandcons '() lst))
(define (doubleandcons lst num rest) ; ignore input lst
(cons (* 2 num) (rest))) ; force the lazy rest
(define (member elt lst)
(para (lambda (xs x r)
(if (equal? x elt) xs (r))) ; conditionally force, or
'() lst)) ; ignore the rest
(define (mymap f lst)
(para
(lambda (xs x r)
(cons (f x) (r))) ; cons the result of calling f w/ x,
'() lst)) ; onto the rest
(define (all pred lst)
(para
(lambda (xs x r)
(and (pred x) (r))) ; possibly short-circuit
#t lst))
您不能与您的版本短路,因为它会在将作为参数传递给组合函数(ff
)之前评估其余的。
答案 2 :(得分:1)
(define u-map
(lambda (ff lst)
(reduce (lambda (x y) (cons (ff x) y)) '() lst)))
列表中的折叠信息为您提供该列表的副本。