我对方案和Lisp有一般性的问题。 fold
和reduce
函数应如何工作?
在使用(use-modules (srfi srfi-1))
的诡计方案中,您可以使用以下方法:
guile> (fold cons '() '(1 2 3 4))
> (4 3 2 1)
guile> (fold cons '(1 2 3 4) '())
> (1 2 3 4)
我正在使用JavaScript在Lisp中处理fold函数,我想为reduce和fold创建单个函数(该函数将返回这些函数之一)。
但是它们应该如何工作?在我的代码中,我正在检查第一个列表是否不为null或是否未结束,但是在这里您传递了空列表(第一个代码)。折叠是否可以在第二个列表上工作,并检查该列表是否还没有结束,或者两个都可以,因为反向操作也可以?当以'()作为初始值调用时执行多少次折叠,或者它处理整个第一个参数?
这是我的reduce函数:
function reduce(fn, list, init = nil) {
if (isEmptyList(list) || isNull(list)) {
return list;
}
let result = init;
let node = list;
if (init === null) {
result = list.car;
node = list.cdr;
}
return (function loop() {
function next(value) {
result = value;
node = node.cdr;
return loop();
}
if (node === nil || !(node instanceof Pair)) {
if (typeof result === 'number') {
return LNumber(result);
}
return result;
}
const item = node.car;
const value = fn(result, item);
if (isPromise(value)) {
return value.then(next);
} else {
return next(value);
}
})();
}
以下结果对reduce
正确吗?
lips> (reduce cons '(1 2 3 4) nil)
((((nil . 1) . 2) . 3) . 4)
lips> (reduce list '(1 2 3 4) nil)
((((nil 1) 2) 3) 4)
lips>
折叠函数应如何工作并在JavaScript中看起来像?方案中的fold
和reduce
的确切逻辑是什么?
这是另一个狡猾的例子:
guile> (fold-right append '(1 2 3 4) '())
(1 2 3 4)
lips> (reduce append '(1 2 3 4) '())
(1 2 3 4)
它在lisp中的作用相同,是否表示我的reduce正确?如何测试我的功能是否正常工作?
在桂尔,我有一个问题:
guile> (fold-right list '(1 2 3 4) '())
> (1 2 3 4)
guile> (fold list '(1 2 3 4) '())
> (1 2 3 4)
但在我的嘴里:
lips> (reduce list '(1 2 3 4) '())
((((() 1) 2) 3) 4)
对折实际上是否减少?因为此代码中的guile与我的reduce产生了相同的结果:
guile> (list (list (list (list '() 1) 2) 3) 4)
> ((((() 1) 2) 3) 4)
答案 0 :(得分:2)
https://www.gnu.org/software/guile/manual/html_node/SRFI_002d1-Fold-and-Map.html
方案过程: fold proc init lst1 lst2 …
方案过程: 右折叠proc init lst1 lst2 …
将 proc 应用于 lst1 lst2 的元素以生成结果,然后返回该结果。
每个 proc 调用都是(proc elem1 elem2 …上一个),其中 elem1 来自 lst1 , elem2 来自 lst2 ,依此类推。 previous是从先前调用 proc 返回的结果,或者是第一次调用的给定init。 如果任何列表为空,则仅返回 init 。
fold
从头到尾遍历列表元素。下面显示了列表反转及其产生的调用,
(fold cons '() '(1 2 3))
(cons 1 '())
(cons 2 '(1))
(cons 3 '(2 1)
⇒ (3 2 1)
fold-right
从最后到第一个遍历列表元素,即。从右边。因此,例如,以下代码找到最长的字符串,而等长的字符串中的最后一个字符串,
(fold-right (lambda (str prev)
(if (> (string-length str) (string-length prev))
str
prev))
""
'("x" "abc" "xyz" "jk"))
⇒ "xyz"
方案折叠支持多个列表,但我将向您展示如何调整JavaScript实现,使其与一个列表一起使用-
function reduce (fn, init, list) {
if (isNull(list))
return init
else
return reduce(fn, fn(list.car, init), list.cdr)
}
function reduceRight (fn, init, list) {
if (isNull(list))
return init
else
return fn(list.car, reduceRight(fn, init, list.cdr))
}
JavaScript支持 rest参数和 spread参数-
,支持多个列表非常容易function some (fn, list) {
if (isNull(list))
return false
else
return fn(list.car) || some(fn, list.cdr)
}
function reduce (fn, init, ...lists) {
if (some(isEmpty, lists))
return init
else
return reduce
( fn
, fn (...lists.map(l => l.car), init)
, lists.map(l => l.cdr)
)
}
function reduceRight (fn, init, ...lists) {
if (some(isEmpty, lists))
return init
else
// exercise left for reader
// ...
}