如何在 Scheme 中使用 reduce 和 curry 为列表中的所有项目创建求和函数?
How to create sum function for all items in list using reduce and curry in Scheme?
我正在玩 Scheme 我想 运行 像这样:
(reduce curry + '(1 2 3))
为什么这不起作用?我也试过 运行 这个:
((curry + 1) 2)
((curry (curry + 1) 2) 3)
((curry (curry (curry + 1) 2) 3) 4)
在LIPS my Scheme implementation it works (see beta version REPL)。为什么这在 Kawa 或 Guile 中不起作用。我的实现不正确吗?我没有对函数调用进行偶数检查。函数总是被调用,是这个原因吗?
我的 curry 函数是用 JavaScript 编写的,但我很快尝试在 Kawa 中创建函数来测试它的实现,这可能比我的要好得多。
添加 check-arg
缺失函数后,我使用 SRFI-1 code on GitHub 中的右折叠代码。
我用的是这个咖喱版本:
(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 方案。我想在标准方案中进行测试,看看我的实现是否正确。
编辑:咖喱的简单实现实际上是错误的。这是正确的实现:
(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.
中的工作方式
我尝试了不同的折叠组合,其中 none 有效。
我用 mit-scheme
尝试过,但我怀疑在其他版本的方案中 meaning of reduce
是相同的。
(reduce curry '+ (list 1 2 3 4))
等同于
(curry (curry 1 2) 3)
“标准”reduce
的定义表明 +
参数仅在列表为空时使用。
因此您需要重新定义 reduce
以便按照您的预期运行。
在 mit-scheme 中,您应该使用 fold-left 代替,如果您希望一直使用 +
运算符,还应柯里化 +
运算符。
在方案的其他版本中 它有效,因为 the + operator is also curried by default
.
这是因为你这样定义 curry:
(define curry
(lambda (f arg1) ;type 1
(lambda (arg2) ;type 2
(f arg1 arg2))))
递归应用它,您将应用 (curry (curry + 1) 2)
。 (curry + 1)
必须 与 +
具有相同的类型(即 +
必须具有类型 2)。我现在在工作,我现在没有时间为你正确定义咖喱,但在接下来的日子里也许我会找到时间。
注意:在正确的定义中,您应该期望 FOLD-LEFT
的输出必须应用于初始元素(0
用于加法)。
在@alinsoar 的帮助下,我在 MIT Scheme docs
中发现了过时的 fold-left
定义
此代码适用于 Kawa:
(require 'list-lib) ;; import SFRI-1
;; this is equivalence of fold-left using fold from MIT Scheme docs
(define (fold-left proc knil list)
(fold (lambda (acc elt) (proc elt acc)) knil list))
(define (curry f . args)
"(curry f . args)
simplified version of curry"
(lambda more-args
(apply f (append args more-args))))
(display ((fold-left curry + '(1 2 3 4))))
(newline)
我正在玩 Scheme 我想 运行 像这样:
(reduce curry + '(1 2 3))
为什么这不起作用?我也试过 运行 这个:
((curry + 1) 2)
((curry (curry + 1) 2) 3)
((curry (curry (curry + 1) 2) 3) 4)
在LIPS my Scheme implementation it works (see beta version REPL)。为什么这在 Kawa 或 Guile 中不起作用。我的实现不正确吗?我没有对函数调用进行偶数检查。函数总是被调用,是这个原因吗?
我的 curry 函数是用 JavaScript 编写的,但我很快尝试在 Kawa 中创建函数来测试它的实现,这可能比我的要好得多。
添加 check-arg
缺失函数后,我使用 SRFI-1 code on GitHub 中的右折叠代码。
我用的是这个咖喱版本:
(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 方案。我想在标准方案中进行测试,看看我的实现是否正确。
编辑:咖喱的简单实现实际上是错误的。这是正确的实现:
(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.
我尝试了不同的折叠组合,其中 none 有效。
我用 mit-scheme
尝试过,但我怀疑在其他版本的方案中 meaning of reduce
是相同的。
(reduce curry '+ (list 1 2 3 4))
等同于
(curry (curry 1 2) 3)
“标准”reduce
的定义表明 +
参数仅在列表为空时使用。
因此您需要重新定义 reduce
以便按照您的预期运行。
在 mit-scheme 中,您应该使用 fold-left 代替,如果您希望一直使用 +
运算符,还应柯里化 +
运算符。
在方案的其他版本中 它有效,因为 the + operator is also curried by default
.
这是因为你这样定义 curry:
(define curry
(lambda (f arg1) ;type 1
(lambda (arg2) ;type 2
(f arg1 arg2))))
递归应用它,您将应用 (curry (curry + 1) 2)
。 (curry + 1)
必须 与 +
具有相同的类型(即 +
必须具有类型 2)。我现在在工作,我现在没有时间为你正确定义咖喱,但在接下来的日子里也许我会找到时间。
注意:在正确的定义中,您应该期望 FOLD-LEFT
的输出必须应用于初始元素(0
用于加法)。
在@alinsoar 的帮助下,我在 MIT Scheme docs
中发现了过时的fold-left
定义
此代码适用于 Kawa:
(require 'list-lib) ;; import SFRI-1
;; this is equivalence of fold-left using fold from MIT Scheme docs
(define (fold-left proc knil list)
(fold (lambda (acc elt) (proc elt acc)) knil list))
(define (curry f . args)
"(curry f . args)
simplified version of curry"
(lambda more-args
(apply f (append args more-args))))
(display ((fold-left curry + '(1 2 3 4))))
(newline)