我正在玩 Scheme 我想运行这样的东西:
(reduce curry + '(1 2 3))
为什么这不起作用?我也尝试运行这个:
((curry + 1) 2)
((curry (curry + 1) 2) 3)
((curry (curry (curry + 1) 2) 3) 4)
在LIPS 我的 Scheme 实现中它可以工作(参见beta 版 REPL)。为什么这在 Kawa 或 Guile 中不起作用。我的实现不正确吗?我没有对函数调用进行数量检查。函数总是被调用,是这个原因吗?
我的 curry 函数是用 JavaScript 编写的,但我很快尝试在 Kawa 中创建函数来测试它的实现,这可能比我的要好得多。
添加缺少的功能后,我使用GitHub 上的 SRFI-1 代码中的右折叠代码。check-arg
我使用了这个咖喱版本:
(define curry (lambda (f arg1) (lambda (arg2) (f arg1 arg2))))
我认为对于简单的测试,这应该没问题。
这应该起作用的一个例子是 JavaScript:
function type(label, arg, type) {
// some type checking so you know which function
// throw exception and why
var arg_type;
if (arg instanceof Array) {
arg_type = 'array';
} else if (arg === null) {
arg_type = 'null';
} else {
arg_type = typeof arg;
}
if (arg_type !== type) {
throw new Error(`${label}: Expecting ${type} got ${arg_type}`);
}
}
function curry(fn, ...init_args) {
type('curry', fn, 'function');
var len = fn.length;
return function() {
var args = init_args.slice();
function call(...more_args) {
args = args.concat(more_args);
//console.log({fn, len, args});
if (args.length >= len) {
return fn.apply(this, args);
} else {
return call;
}
}
return call.apply(this, arguments);
};
}
function add(...args) {
return args.reduce((a,b) => a + b);
}
console.log(curry(curry(curry(curry(add, 1), 2), 3), 4)());
console.log([1,2,3,4].reduce((a,b) => curry(a,b), add)());
相同的代码在我的 LIPS 中有效:
((--> #(1 2 3 4) (reduce (lambda (a b) (curry a b)) +)))
((--> #(1 2 3 4) (reduce (binary curry) +)))
注意: -->是在数组上调用 reduce 的宏(Scheme 中的向量是数组和-->调用方法)。需要 lambda 和二进制函数(受 Ramda 库的启发),因为 Array::reduce 添加了给定数组的第三个参数。
我的问题是为什么这在卡瓦不起作用,我做错了什么?
我需要补充一点:
(reduce curry + '(1 2 3))
也不能在 LIPS 中工作,我不知道为什么,但我主要是在询问标准 R7RS 方案。我想在标准方案中进行测试,看看我的实现是否正确。
编辑: curry 的简单实现实际上是错误的。这是正确的实现:
(define (curry f . args)
(lambda more-args
(apply f (append args more-args))))
((curry (curry (curry + 1) 2) 3) 4)
;; ==> 10
这也是简化版本的正确函数,它应该在调用函数之前检查参数的长度,如果它小于原始函数,它应该继续返回 lambda(不确定你是否可以在 Scheme 中检查参数的长度)。上面的代码适用于 Guile 和 Kawa。
所以另一个问题(仍然存在)是如何使 JavaScript 之类的东西在 Scheme 中减少工作?
EDIT2:这是有效的功能:
(define (fld fn init l)
(do ((l l (cdr l))
(result init (fn result (car l))))
((null? l) result)))
((fld curry + '(1 2 3 4)))
;; ==> 10
在 Kawa 和 Guile 测试。
你知道用默认函数在Scheme中制作像fld这样的标准方法吗(不定义新函数,除了curry)?对我来说,reduce 应该如何工作,这就是它在 JavaScript 中的工作方式。
我尝试了不同的折叠组合,但它们都不起作用。