【问题标题】:Building map with Racket使用 Racket 构建地图
【发布时间】:2017-02-28 10:35:32
【问题描述】:

我在实践中构建地图功能。

我想出了以下代码:

#lang racket

(define (map procedure items)
  (if (null? items)
      empty
      (cons (procedure (car items)) (map procedure (cdr items)))))

我试过了,效果很好:

(map add1 '(1 2 3))

>> '(2 3 4)

然后我尝试了这个,它也很好用:

(define (scale-by-3 item)
  (* 3 item))

(map scale-by-3 '(1 2 3))

>> '(3 6 9)

在那之后,我决定概括一下缩放过程:

(define (scale-by-factor factor item)
  (* factor item))

这个比例因子函数有效:

(scale-by-factor 3 4)

>> 12

但是当我尝试将它与地图一起使用时:

(map (scale-by-factor 2 item) '(1 2 3))

我收到以下错误:

item: unbound identifier in module in: item

我该如何解决这个问题?没有 lambda 有没有办法解决?

【问题讨论】:

  • Racket 和 Lisp 的答案会有所不同。 Lisp 程序员可能会写一个anaphoric macro

标签: functional-programming lisp racket sicp


【解决方案1】:

它失败是因为 item 在您调用它时不存在 - 它在遍历列表时由 map 作为参数传递。要解决此问题,请执行以下操作:

(map (lambda (item) (scale-by-factor 2 item))
     '(1 2 3))

或者我们可以使用curry 编写一个更好的替代方案,它会创建一个lambda,它需要缺少item 参数:

(map (curry scale-by-factor 2)
     '(1 2 3))

【讨论】:

    【解决方案2】:

    首先,item确实没有绑定。你没有在任何地方定义它。

    你想要的是scale-by-factor 的部分应用。此函数接受两个参数并计算结果。但是,如果您仅将它部分应用于一个参数,它将评估为一个接受另一个参数并评估最终结果的函数。

    您可以在 Racket 中使用 curry 来实现此目的,如 here 所示。

    (define (map procedure items)
      (if (null? items)
        empty
        (cons (procedure (car items)) (map procedure (cdr items)))))
    
    (define (scale-by-factor factor item)
      (* factor item))
    
    (map (curry scale-by-factor 5) '(1 2 3))
    

    之所以叫curry,是因为this

    【讨论】:

    • 没错。只是我写的时候,你的答案还没有呈现在网站上。
    【解决方案3】:

    这里有很好的解决方案。我将提供一些替代方案,以便您可以看到更多做同样事情的方法

    你可以用柯里化的形式定义scale-by-factor函数

    (define ((scale-by-factor x) y)
      (* x y))
    
    ; note it needs two applications to get the computed result now
    ((scale-by-factor 3) 4)
    ; => 12
    

    您可以在其他问题之一上使用CPS technique I showed you 定义尾递归映射

    (define (map f xs)
      (let iter ([xs xs] [k identity])
        (if (empty? xs)
            (k empty)
            (let ([v (f (car xs))])
              (iter (cdr xs) (λ (rest) (k (cons v rest))))))))
    
    (map (scale-by-factor 2) '(1 2 3))
    ; => '(2 4 6)
    

    【讨论】:

      【解决方案4】:

      在 Racket 中for/list 可用于创建地图功能:

      (define (mymap proc lst)
        (for/list ((item lst))
          (proc item)))
      
      (mymap add1 '(1 2 3))
      ; =>'(2 3 4)
      

      【讨论】:

        猜你喜欢
        • 2017-02-28
        • 1970-01-01
        • 2017-02-20
        • 1970-01-01
        • 1970-01-01
        • 2017-02-21
        • 2017-04-27
        • 2020-03-30
        • 1970-01-01
        相关资源
        最近更新 更多