使用普通 lisp 展平列表 [英] Flatten a list using common lisp

查看:17
本文介绍了使用普通 lisp 展平列表的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在阅读 Paul Graham 的 On Lisp 一书.在第 4 章实用函数中,他给出了对列表进行操作的小函数的示例,这在编写更大的程序时会很有帮助.

I was reading the book On Lisp by Paul Graham. In Chapter 4, Utility Functions, he gives examples of small functions that operate on lists, which would be helpful while writing a larger program.

其中之一是flatten.给定任意级别的嵌套列表作为参数, flatten 将删除所有嵌套元素并将它们放在顶层.

One of them is flatten. Given a nested list at any arbitrary level as argument, flatten will remove all the nested elements and put them on the top level.

以下是我实现扁平化的尝试:

Below is my attempt at implementing flatten:

(defun flatten (lst)
  (labels ((rflatten (lst1 acc)
                     (dolist (el lst1)
                       (if (listp el)
                         (rflatten el acc)
                         (push el acc)))
                     acc))
    (reverse (rflatten lst nil))))

但是上面的函数没有正确地展平列表.

But the above function does not flatten lists properly.

; returns (1) instead of (1 2)
(print (flatten '(1 (2))))
(1)

使用(1 (2)) 调用函数返回(1) 而不是(1 2).

Calling the function with (1 (2)) returns (1) instead of (1 2).

我找不到我的 flatten 实现有什么问题.这是我使用的方式吗标签?还是我使用 dolist 宏的方式?dolist 宏总是返回 nil.但这并不重要,因为我使用累加器 acc 来存储扁平列表.

I cannot find what's wrong with my implementation of flatten. Is it the way I am using labels? Or is it the the way I am using the dolist macro? The dolist macro always returns nil. But that should not matter as I am using an accumulator acc to store the flattened list.

推荐答案

push 更改作用域中的符号绑定.因此递归 (rflatten el acc) 有它自己的 acc 这是那里的结果,但你不对返回的结果做任何事情,它也不会改变被调用者acc.

push changes the symbol binding in scope. Thus the recursion (rflatten el acc) has it's own acc which is the result there but you don't do anything with the returned result and it doesn't alter the callee acc.

也许 (setf acc (rflatten el acc)) 可以解决这个问题:

Perhaps a (setf acc (rflatten el acc)) would fix that:

(defun flatten (lst)
  (labels ((rflatten (lst1 acc)
             (dolist (el lst1)
               (if (listp el)
                   (setf acc (rflatten el acc))
                   (push el acc)))
             acc))
    (reverse (rflatten lst nil))))

这篇关于使用普通 lisp 展平列表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆