常见的lisp:如何实现reduce

时间:2017-01-23 20:22:09

标签: list functional-programming lisp common-lisp reduce

我一直在寻找这个好几天,基本上我需要实现一个与系统功能减少相同的功能。这是我到目前为止所提出的,但没有初始值i我无法让它工作。

这是我的代码

(defun my-reduce (p i lista)
  (if (null lista)
       i
    (funcall p (car lista) (my-reduce p i (cdr lista)))))

顺便说一下,它甚至没有正常工作,因为它“向后” 例如:

(my-reduce #'list NIL '(1 2 3 4))

应该返回

  

(((1 2)3)4)

但我得到

  

(1(2(3(4 NIL))))

任何想法?

2 个答案:

答案 0 :(得分:3)

左侧折叠可以通过简单的迭代实现:

(defun my-fold-left (reducer initial list)
  (loop for fold = initial then (funcall reducer fold element)
        for element in list
        finally (return fold)))

例如:

(my-fold-left #'cons 0 '(1 2 3 4))
((((0 . 1) . 2) . 3) . 4)

(my-fold-left #'cons 0 '())
0

如果使用map

,也可以对向量进行推广和折叠
(defun my-fold-left (reducer fold sequence)
  (map nil
       (lambda (e) (setf fold (funcall reducer fold e)))
       sequence)
  fold)

如果您没有阅读,this answer对左右折叠有一个很好的高级解释。

答案 1 :(得分:1)

我认为你已经实现了正确的右侧折叠,因为这通常被称为,但是需要左侧折叠。注意特征尾递归,并使用“默认”值作为累加器:

(defun my-left-reduce (f i xs)
  (if (null xs)
       i
    (my-left-reduce f (funcall f i (car xs)) (cdr xs))

(我从未使用过Common Lisp,但这个概念应该很明确。)

除此之外:通常是左侧折叠被认为是“向后”。比较(my-reduce cons NIL '(1 2 3))(my-left-reduce cons NIL '(1 2 3))。后者应该颠倒列表的原始缺陷结构。