【问题标题】:Lists and Member Implementation in Common LispCommon Lisp 中的列表和成员实现
【发布时间】:2013-05-22 00:53:08
【问题描述】:

我刚刚开始学习 Common Lisp,我正在阅读的文本使用了带有 member 函数的示例。

我不确定这两个代码块之间的区别:

(if (member nil '(1 nil 2 3))
    'contains-nil
    'does-not-contain-nil)

返回 CONTAINS_NIL

(if (member nil '(1 2 3))
    'contains-nil
    'does-not-contain-nil)

返回 DOES-NOT-CONTAIN-NIL

据我了解,列表相当于嵌套的cons 单元格,所以我认为(member nil (cons 1 (cons 2 (cons 3 nil))) 会返回(nil),但它只是返回nil。我不确定编译器或解释器如何做出这种区分,如果有人能给我一些关于如何实现 member 函数的见解,我将不胜感激。

【问题讨论】:

    标签: lisp common-lisp


    【解决方案1】:

    一个 cons 单元格包含两个值,通常称为 carcdr。表达式(cons x y) 返回一个cons 单元格,其carx,其cdry。在 Lisp 中,list 要么是空列表(通常是符号 nil),要么是一个 cons 单元格。当列表为 cons 单元格时,列表的 first 元素是 cons 单元格的 car,列表的 rest 是 cons 单元格的 cdr。考虑列表(1 2 3)。它是一个 cons 单元格,列表的第一个元素是 1。列表的其余部分不为空,因此它必须是另一个列表,其第一个元素是2。该列表的其余部分不为空,因此它必须是另一个列表,其第一个元素是3。该列表的其余部分 为空,即 nil。基于该分析,我们可以看到为什么列表是由

    (cons 1 (cons 2 (cons 3 nil)))
    == (1 2 3)
    

    在组成列表的 cons 单元链中,列表的元素是链中每个 cons 单元的 car 值。列表可以是列表的元素,如

    (cons 1 (cons nil (cons 2 (cons 3 nil))))
    == (1 nil 2 3)
    

    (cons 1 (cons (cons 2 (cons 3 nil)) nil))
    == (1 (2 3))
    

    但仅仅因为我们在较长的表达式中看到nil 并不意味着nil 是列表的一个元素。

    【讨论】:

    • 所以要在解释器中实现这个,你会得到一些类似于(if (equal (cdr list) nil) 'list-over 'list-not-over))
    • 如果list-over 的意思是“这个列表的其余部分是空的”,那么是的。 Common Lisp 为此提供了函数endp,当然:(endp nil) => t,和(endp nil) => nil
    • @JoshuaTaylor 最后一条评论有错别字。第二个代码示例应该是,例如,(endp '(1 . 2)) => nil
    【解决方案2】:

    MEMBER 只查看列表的元素,而不查看列表本身。空列表不同于以另一个空列表为元素的空列表。

    ()(()) 不同。 ()(nil) 不同。

    由于列表由 cons 单元格组成,因此元素是 cons 单元格的cars

    【讨论】:

      【解决方案3】:

      列表被定义为空列表 NIL 或者是一个 cons 单元,其 CAR 是列表的一个元素,其 CDR 是另一个列表。 由

      生成的列表
      (cons 1 nil)
      

      是一个包含元素 1 以及空列表的所有元素的列表。空列表没有元素,因此 NIL 不是列表的元素。 与集合类似:尽管空集合是任何集合的子集,但它不是每个集合的元素(虽然通常不禁止它成为集合的元素)。

      实现 MEMBER 的一种方式如下:

      (defun member (item list)
        (if list
            (if (eql item (car list))
                list
                (member item (cdr list)))))
      

      因此,如果 LIST 为 NIL,则整个函数将返回 NIL。

      【讨论】:

      • 空集合没有理由成为另一个集合的元素,就像空列表nil可能是另一个列表的元素一样。它应该改为:虽然空集是每个集合的子集,但它不是每个集合的元素(但可能是一些元素)。
      • 感谢您指出这一点。我不知道我为什么要这样写。
      【解决方案4】:

      我们自己的 lisp 中预定义成员函数的版本可以定义为:

      (defun member2 (item lst)
        (if lst
            (if (eql item (car lst))
                T
                (member2 item (cdr lst)))))
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2023-03-23
        • 1970-01-01
        • 2020-08-16
        • 1970-01-01
        • 2019-01-18
        • 2017-06-08
        • 2021-12-25
        • 2013-05-16
        相关资源
        最近更新 更多