将咖喱映射到参数列表

bri*_*tar 2 scheme functional-programming currying racket

我在Racket做了一些练习,遇到了一个我似乎无法查询文档的问题.

我想modulo为一个除数列表生成以下的curries:

(define multlist '[3 5])
(define modfuncs (map (lambda x ;@ make some modulos
                          (curry modulo x)) multlist))
Run Code Online (Sandbox Code Playgroud)

这会生成一个curried程序列表,听起来很有希望,但是当我尝试测试其中一个时,我收到以下错误:

-> (car modfuncs)
#<procedure:curried>
-> ((car modfuncs) 3)
; modulo: contract violation
;   expected: integer?
;   given: '(3)
;   argument position: 1st
; [,bt for context]
Run Code Online (Sandbox Code Playgroud)

假设这不是一种可怕的方法,我如何取消引用multlist传递给curry/ mapcall 的值,以便这些函数能够正确计算?

Ale*_*ing 5

你实际上是这样做的,尽管有一个小小的错误:

(lambda x (curry modulo x))
Run Code Online (Sandbox Code Playgroud)

这不符合你的想法.你真正想要的是这个:

(lambda (x) (curry modulo x))
Run Code Online (Sandbox Code Playgroud)

看到不同?在前者中,x不在参数列表中,因此它实际上将传递给传递给函数所有参数的列表,而不是单个参数.

您可以使用以下简单程序自己查看此行为:

((lambda x x) 1 2 3)
; => '(1 2 3)
Run Code Online (Sandbox Code Playgroud)

因此,您的curry函数正在接收一个数字的列表x,而不是实际的整数.


所以也许更令人满意的答案是:为什么Racket会这样做?嗯,这实际上是Racket/Scheme的rest参数语法的结果.在lambda的最后一个参数之前插入一个点使该参数成为rest参数,该参数成为一个列表,其中包含传递给函数的所有其他参数.

((lambda (a b . rest) rest) 1 2 3 4 5)
; => '(3 4 5)
Run Code Online (Sandbox Code Playgroud)

但是,这实际上并不仅仅是一种特殊的语法.点符号实际上与Racket读者如何读取语法中的列表和对有关.以上参数列表实际上变成了由以下缺点序列组成的"不正确"列表:

(cons 'a (cons 'b 'rest))
Run Code Online (Sandbox Code Playgroud)

没有rest参数的相同函数将有一个正确的列表作为其参数声明,它将如下所示:

(cons 'a (cons 'b null))
Run Code Online (Sandbox Code Playgroud)

那么,原来x只是独自站立怎么样?那么,这是一个没有先前参数的不正确的列表!这样做( . rest)没有任何意义 - 这将是一个语法错误 - 因为你试图创建一个没有car元素的对.等效的只是完全删除对语法.