【问题标题】:Why is my lisp function returning 'NIL'为什么我的 lisp 函数返回“NIL”
【发布时间】:2017-02-11 22:24:18
【问题描述】:

我正在编写一个 lisp 函数,它将在不使用“reverse”函数的情况下确定一个单词是否是回文。我对 lisp 还很陌生,我仍在努力掌握这个概念。每次我测试回文时,该函数都会返回NIL,有什么想法吗?

我想出的功能。

(defun palindromep (list)
    (cond
        ((null list)t)
        (t
            (and (equal (first list) (first (rest list)))
                (palindromep (butlast (rest list)))))))

代码修订

(defun palindromep (list)
    (cond
        ((null list)t)
        (t
            (and (equal (first list) (first(last list)))
                (palindromep (butlast(rest list)))))))

【问题讨论】:

    标签: list lisp common-lisp clisp


    【解决方案1】:

    我怎么看它似乎在一组特殊的回文中起作用,其中有偶数个相同类型的元素。

    您需要为一个元素列表返回t。 IE。 (null (cdr list))

    您的检查检查两个第一个元素是否相同,而不是第一个和最后一个元素是否相同。

    编辑

    我能想到的最好的使用递归和不使用反向的方法是这样的:

    (defun palindromep (list)
      (labels ((aux (history tortoise hare)
                 (cond ((null hare) (equal tortoise history))
                       ((null (cdr hare)) (equal (cdr tortoise) history))
                       (t (aux (cons (car tortoise) history)
                               (cdr tortoise)
                               (cddr hare))))))
        (aux '() list list)))
    

    它的工作原理是通过一个额外的光标hare 迭代两倍于tortoise 的距离,同时在history 中累积所见元素。由于cons 从头到尾创建列表,因此历史记录是所有反向元素,因此当您到达中间时应该匹配结尾。当 hare 的 cdrcddr 为 null 时,您处于中间位置,可以通过简单的比较来确定回文。

    编辑 2

    如果您将助手移出,则更容易跟踪并查看发生了什么:

    (defun aux (history tortoise hare)
      (cond ((null hare) (equal tortoise history))
            ((null (cdr hare)) (equal (cdr tortoise) history))
            (t (aux (cons (car tortoise) history)
                    (cdr tortoise)
                    (cddr hare)))))
    
    (defun palindromep (list)
      ;; just calls helper
      (aux '() list list))
    
    ;; trace the helper
    (trace aux)
    (trace equal) ; you might need to follow instructions to unlock
    
    (palindromep '(1 2 3 3 2 1))
      0: (AUX NIL (1 2 3 3 2 1) (1 2 3 3 2 1))
        1: (AUX (1) (2 3 3 2 1) (3 3 2 1))
          2: (AUX (2 1) (3 3 2 1) (2 1))
            3: (AUX (3 2 1) (3 2 1) NIL)
              4: (EQUAL (3 2 1) (3 2 1))
              4: EQUAL returned T
            3: AUX returned T
          2: AUX returned T
        1: AUX returned T
      0: AUX returned T
    ==> T
    
    (palindromep '(1 2 3 4 5 6))
      0: (AUX NIL (1 2 3 4 5 6) (1 2 3 4 5 6))
        1: (AUX (1) (2 3 4 5 6) (3 4 5 6))
          2: (AUX (2 1) (3 4 5 6) (5 6))
            3: (AUX (3 2 1) (4 5 6) NIL)
              4: (EQUAL (4 5 6) (3 2 1))
              4: EQUAL returned NIL
            3: AUX returned NIL
          2: AUX returned NIL
        1: AUX returned NIL
      0: AUX returned NIL
    ==> NIL
    

    【讨论】:

    • 我修改了我的代码,现在它告诉我我输入的每一个东西都是回文,有什么建议吗?
    • @RileyThomas 那是因为递归的参数是正确的,但现在不再正确了。递归不再仅在第一个元素出现时才进行,而是一直进行到您遇到基本情况,即空列表。此外,对一个元素列表的测试应该与对空列表的测试一起进行。 (or a b)cond 中的单独术语。现在它总是在默认情况下完成,而不是作为尾部表达式。
    • 我所做的修改现在似乎可以工作了。关于如何重写函数的最后一行以使其仍然执行相同操作的任何建议?
    • @RileyThomas 似乎默认情况没问题。您需要检查(or (null list) (null (cdr list))) 而不仅仅是(null list),它也适用于奇数元素回文。因为你只有两个术语 if 与 if 一样好用
    • 好的,我会把它包括在内,还有其他方式我可以说(palindromep (butlast(rest list)) 吗?
    猜你喜欢
    • 2018-02-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-25
    • 2012-09-15
    • 1970-01-01
    • 2019-02-28
    • 1970-01-01
    相关资源
    最近更新 更多