在 Racket 中推广映射值
Generalizing map-values in Racket
假设我有以下功能:
(define foo
(lambda (n)
(values n (* 2 n))))
我想在列表 '(1 2 3 4)
上调用地图 foo
。因此,我创建了一个 map-values
函数:
(define map-values
(lambda (f xs)
(match xs
['() (values '() '())]
[(cons x xs)
(let-values ([(a b) (f x)]
[(as bs) (map-values f xs)])
(values (cons a as) (cons b bs)))]
)))
现在,我可以执行以下操作:
(map-values foo '(1 2 3 4)) => (values '(1 2 3 4) '(2 4 6 8))
但是,如果 foo
returns 三个值,或四个,...等等?我需要为每个案例创建一个新的 map-values
函数。有没有一种方法可以概括 map-values
以便它可以与 returns 多个值的任何 foo
一起使用?
这就是你想要的:
(define (map-values proc lst)
(define (wrap e)
(call-with-values (lambda () (proc e)) list))
(apply values
(apply map list (map wrap lst))))
(define (foo n)
(values n (* 2 n) (/ 1 n)))
(map-values foo '(1 2 3 4))
; ==> (1 2 3 4)
; ==> (2 4 6 8)
; ==> (1 1/2 1/3 1/4)
这也与标准方案兼容。
假设我有以下功能:
(define foo
(lambda (n)
(values n (* 2 n))))
我想在列表 '(1 2 3 4)
上调用地图 foo
。因此,我创建了一个 map-values
函数:
(define map-values
(lambda (f xs)
(match xs
['() (values '() '())]
[(cons x xs)
(let-values ([(a b) (f x)]
[(as bs) (map-values f xs)])
(values (cons a as) (cons b bs)))]
)))
现在,我可以执行以下操作:
(map-values foo '(1 2 3 4)) => (values '(1 2 3 4) '(2 4 6 8))
但是,如果 foo
returns 三个值,或四个,...等等?我需要为每个案例创建一个新的 map-values
函数。有没有一种方法可以概括 map-values
以便它可以与 returns 多个值的任何 foo
一起使用?
这就是你想要的:
(define (map-values proc lst)
(define (wrap e)
(call-with-values (lambda () (proc e)) list))
(apply values
(apply map list (map wrap lst))))
(define (foo n)
(values n (* 2 n) (/ 1 n)))
(map-values foo '(1 2 3 4))
; ==> (1 2 3 4)
; ==> (2 4 6 8)
; ==> (1 1/2 1/3 1/4)
这也与标准方案兼容。