将 curry 映射到参数列表

Mapping curry to a list of parameters

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

我想为除数列表生成 modulo 的以下咖喱:

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

这会生成一个柯里化过程列表,听起来很有希望,但是当我尝试测试其中一个时,出现以下错误:

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

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

你实际上做对了,尽管有一个小错误:

(lambda x (curry modulo x))

这与您认为的不同。你实际上想要的是:

(lambda (x) (curry modulo x))

看出区别了吗?在前者中,x 不在参数列表中,因此它实际上将传递一个 传递给函数的所有参数的列表 ,而不是单个参数。

您可以通过以下简单程序亲眼看到这种行为:

((lambda x x) 1 2 3)
; => '(1 2 3)

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


所以也许更令人满意的答案是:Racket 为什么要这样做?好吧,这实际上是 Racket/Scheme 的 rest parameter syntax 的结果。在 lambda 的最后一个参数之前插入一个点使该参数成为 剩余参数,它成为一个包含传递给函数的所有附加参数的列表。

((lambda (a b . rest) rest) 1 2 3 4 5)
; => '(3 4 5)

然而,这实际上不仅仅是一种特殊的语法。点符号实际上与 Racket 的 reader 如何读取语法中的列表和对有关。上面的参数列表实际上变成了一个"improper"列表,由下面的cons序列组成:

(cons 'a (cons 'b 'rest))

没有 rest 参数的相同函数将有一个 适当的 列表作为其参数声明,它看起来像这样:

(cons 'a (cons 'b null))

那么,原来的x一个人呢?好吧,这是一个不正确的列表,没有前面的参数!执行 ( . rest) 没有任何意义——这将是一个语法错误——因为你试图创建一个没有 car 元素的对。等价于完全删除对语法。