【问题标题】:LISP: Why can't I use cons on an empty list?LISP:为什么我不能在空列表上使用 cons?
【发布时间】:2016-06-28 21:32:56
【问题描述】:

我正在尝试通过在 LISP 中使用以下代码添加到一个空列表来构造一个唯一的元素列表:

    ;;;MEMSET - return T if an atom is a top-level member of a set, else NIL
    ;;;This is needed for the makeset function
    (DEFUN MEMSET (ATM L)
        (COND ( ( NULL L) NIL )
              ( (EQL ATM(CAR L)) T )
              ( T    (MEMSET ATM (CDR L)) )
        )
    )
    (DEFUN MAKESET(SET1)
        (DO ((UNIQ ()))
            ( (NULL SET1) UNIQ) 
            (COND ( (NOT (MEMSET (CAR SET1) UNIQ))
                      (CONS (CAR SET1) UNIQ)
                  )
            )
        (SETF SET1 (CDR SET1))
        ) 
    )

当我调用 (makeset '(abbacdba)) 时,此特定代码导致 NIL - 它应该导致 (abcd),不考虑顺序) - 但在我看来,它应该是从 SET1 添加一个原子尚未在每次迭代的 UNIQ 中。您不能添加到在 do 循环中声明的空列表中,还是我遇到了其他问题?顺便说一句,我正在使用 clisp。

【问题讨论】:

  • 请把标题改成事实。这可能需要首先找到真实的真相(通过剥离所有不相关的内容)。
  • 除了前面的注释,请修复代码格式:小写、缩进、挂括号。 Emacs 应该会有所帮助。
  • 简短的回答是(cons x y) 没有修改任何东西;它返回一个新的cons-cell。之后xy 与之前相同。结果是您想要的新值。这意味着你需要像 (setq y (cons x y)) 这样的东西。
  • 谢谢大家的帮助。我意识到格式有点不稳定。这是我编写的第一个 LISP 程序之一。

标签: lisp common-lisp


【解决方案1】:

所有更新都可以通过DO 中的步进表格完成。不需要PUSHSETF

(defun makeset (set1)
  (do ((uniq nil (if (memset (car set2) uniq)
                      uniq
                    (cons (car set2) uniq)))
       (set2 set1 (cdr set2)))
      ((null set2) uniq)))

【讨论】:

    【解决方案2】:

    1.使用正确的格式

    在询问有关 Common-Lisp 的问题时,请使用正确的格式。 例如,参见谷歌搜索返回的前三页 "common lisp formatting conventions"

    以下是应用于您的函数的常规格式示例:

    ;;; Memset - return T if an atom is a top-level member of a set, else NIL
    ;;; This is needed for the makeset function
    
    (defun memset (atm l)
      (cond ((null l) nil)
            ((eql atm (car l)) t)
            (t (memset atm (cdr l)))))
    
    (defun makeset (set1)
      (do ((uniq ()))
          ((null set1) uniq)
        (cond ((not (memset (car set1) uniq))
               (push (car set1) uniq)))
        (setf set1 (cdr set1))))
    

    2。尽可能使用原始函数

    您的两个函数在 Common-Lisp 中都是原始的。

    remove-duplicates 返回一个没有重复元素的列表,member 检查一个元素是否属于一个集合。

    3.您的函数中的错误

    如果你仍然想使用你的函数,而不是remove-duplicates,这就是它的问题。

    如果你想修改一个列表,你应该使用一个修改某些东西的函数。 cons 函数构建了一个新对,但 不修改任何内容。因此,在您的表单(cons (car set1) uniq) 中,您向uniq 添加了一个新元素,因为您获得了一个新列表,其中(car set1) 作为第一个元素,unique 的元素作为其余元素列表,但是这个新列表会立即被丢弃,因为它没有分配给任何东西。

    您可以通过使用宏 setf 将新值分配给局部变量 uniq 来更改此设置:

    (setf uniq (cons (car set1) uniq))
    

    或者你可以写一个等价的形式,通过使用宏push:

    (push (car set1) uniq)
    

    最后,请注意,makeset 函数中的cond 可以替换为更简洁的when,从而产生这个函数:

    (defun makeset (set1)
      (do ((uniq nil))
          ((null set1) uniq)
        (when (not (memset (car set1) uniq))
          (push (car set1) uniq))
        (setf set1 (cdr set1))))
    

    【讨论】:

    • 还有unless 或将do 替换为(let ... (dolist (x set1) ...))
    • 非常感谢。我将研究如何格式化我的代码,使其更具可读性。我很欣赏您编写的示例代码。这是我最早用 LISP 编写的程序之一,所以我还有很多东西要学。
    猜你喜欢
    • 1970-01-01
    • 2015-04-16
    • 2010-11-21
    • 1970-01-01
    • 2012-05-18
    • 1970-01-01
    • 1970-01-01
    • 2018-01-08
    • 2013-07-28
    相关资源
    最近更新 更多