【问题标题】:Common lisp: How to implement reduceCommon lisp:如何实现reduce
【发布时间】:2017-06-08 11:13:48
【问题描述】:

我已经找了好几天了,基本上我需要实现一个函数,它与系统函数 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))))

有什么想法吗?

【问题讨论】:

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


    【解决方案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))。后者应该反转列表的原始 cons 结构。

    【讨论】:

    • 非常感谢!!有没有一种方法可以在输出中不显示NIL
    • @user7337963 标准函数采用关键字参数:initial-value,如果未设置,就好像您使用列表中的cdr 调用它并使用car 作为初始值。当关键字参数 :from-end 设置为 true 时,它​​会像右折叠一样执行元素。
    • @Sylwester 谢谢你,我把你告诉我的和 phg​​ 的解决方案结合起来,我用 2 个参数创建了一个函数,调用 my-reduce !
    • @user7337963 这行得通。您也可以在内部使用 labels 定义助手
    【解决方案2】:

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

    (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 对左右折叠有很好的高级解释。

    【讨论】:

    • 谢谢!不幸的是,我不允许使用 setf
    • 你被允许,在课堂之外;-)
    • 哦,是的,这是肯定的 :) 但不幸的是,对于我的所有课堂作业,我不允许使用循环,设置 setf 或 setq...无论如何我会记住你的答案
    猜你喜欢
    • 2023-03-23
    • 2020-12-18
    • 2020-08-16
    • 2016-12-22
    • 2013-08-10
    • 1970-01-01
    • 2019-01-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多