根据减少来定义地图

时间:2014-02-19 09:47:32

标签: scheme higher-order-functions

我刚刚接过约翰休斯的文章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)

这可能吗?或者也许我错过了这一点?

3 个答案:

答案 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)))

列表中的折叠信息为您提供该列表的副本。