了解方案中的折叠和减少功能

时间:2019-04-21 11:17:27

标签: javascript scheme lisp reduce fold

我对方案和Lisp有一般性的问题。 foldreduce函数应如何工作?

在使用(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中看起来像?方案中的foldreduce的确切逻辑是什么?

这是另一个狡猾的例子:

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)

1 个答案:

答案 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
    // ...
}