用 Racket 构建地图
Building map with Racket
我在练习构建地图功能。
我想出了以下代码:
#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就能解决的方法?
失败是因为 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))
首先,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
这里有很棒的解决方案。我将提供一些替代方案,以便您可以看到更多的方法来做同样的事情
您可以用柯里化形式定义 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
您可以使用 在您的其他问题之一上定义尾递归映射
(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)
在Racket中for/list
可以用来创建地图函数:
(define (mymap proc lst)
(for/list ((item lst))
(proc item)))
(mymap add1 '(1 2 3))
; =>'(2 3 4)
我在练习构建地图功能。
我想出了以下代码:
#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就能解决的方法?
失败是因为 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))
首先,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
这里有很棒的解决方案。我将提供一些替代方案,以便您可以看到更多的方法来做同样的事情
您可以用柯里化形式定义 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
您可以使用
(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)
在Racket中for/list
可以用来创建地图函数:
(define (mymap proc lst)
(for/list ((item lst))
(proc item)))
(mymap add1 '(1 2 3))
; =>'(2 3 4)