在没有MAPCAR

时间:2018-04-05 10:09:57

标签: recursion common-lisp

我试图制作一个程序,用A替换列表L中的元素T的所有实例,而不是NIL的元素。赌注是不使用mapcar

这是我之前做的。我将所有TNIL存储在新列表POS中,然后返回POS

(defun SRC (A L) 
  (defun _SRC (A L POS) 
    (COND ((NOT (EQUAL (CAR L) NIL))
           (_SRC A (CDR L) (APPEND POS (LIST (EQUAL A (CAR L)))))) 
          ((EQUAL (CAR L) NIL)
           (APPEND POS (LIST (EQUAL A NIL))))
          (T POS)))
  (CDR (_SRC A L (LIST NIL))))

目前的行为: 除了搜索NIL本身之外,该程序运行良好,但这种特殊情况并不重要。

我的代码运行的示例很少: -

   (SRC 'g '(a g g o t g))
> (nil t t nil nil t)

在列表中搜索NIL时: -

   (SRC nil '(t a t nil nil))
> (nil nil nil t)

在这个单一的情况下,我们的程序结束于在列表中找到第一个NIL,对于其他搜索,程序工作正常。所以我尝试在列表列表中添加搜索功能。

我更新的代码,用于在没有mapcar的列表列表中进行搜索:

(defun SRC (A L) 
 (defun _SRC (A L POS) 
   (COND ((LISTP (CAR L))
          (APPEND POS (LIST (SRC A (CAR L))))) 
         ((NOT (EQUAL (CAR L) NIL)) 
          (_SRC A (CDR L) (APPEND POS (LIST (EQUAL A (CAR L)))))) 
         ((EQUAL (CAR L) NIL) 
          (APPEND POS (LIST (EQUAL A NIL))))
         (T POS)))
 (CDR (_SRC A L (LIST NIL))))

现在,我期望从这段代码得到的输出如下:

  (SRC 'e '(a b e c (e g e) h t e))
> (nil nil t nil (t nil t) nil nil t)

相反,我的代码永远运行,导致堆栈溢出,我无法找出任何带有callstacks或回溯的东西。

1 个答案:

答案 0 :(得分:7)

由于缺少缩进而无法读取代码。

您的代码无法读取,因为您的代码没有缩进。

(defun SRC (A L) 
(defun _SRC (A L POS) 
(COND ((NOT (EQUAL (CAR L) NIL)) (_SRC A (CDR L) (APPEND POS (LIST (EQUAL A (CAR L)))))) 
      ((EQUAL (CAR L) NIL) (APPEND POS (LIST (EQUAL A NIL))))
      (T POS)))
(CDR (_SRC A L (LIST NIL))))

让我们缩进你的代码。

(defun SRC (A L) 
  (defun _SRC (A L POS) 
    (COND ((NOT (EQUAL (CAR L) NIL))
           (_SRC A (CDR L) (APPEND POS (LIST (EQUAL A (CAR L)))))) 
          ((EQUAL (CAR L) NIL)
           (APPEND POS (LIST (EQUAL A NIL))))
          (T POS)))
  (CDR (_SRC A L (LIST NIL))))

风格和基本错误

基本错误或编程风格问题:

  • defun不应嵌套。 defun不用于定义本地函数。 defun应仅用于全局功能。使用fletlabels进行本地功能。
  • 使用firstrest代替carcdr
  • 使用说话变量
  • 使用小写

不要以嵌套函数开头

我会在没有嵌套函数的情况下开始。

(defun _src (element list pos) 
  (cond ((not (equal (first list) nil))
         (_src a (rest list) (append pos (list (equal element (car list)))))) 
        ((equal (first list) nil)
         (append pos (list (equal element nil))))
        (t pos)))

(defun src (element list)
  (cdr (_src element list (list nil))))

简化递归

但是你可以使用通常的递归模式大大简化它:

(defun mark% (element list result) 
  (if (null list)                            
      result                                  ; empty list -> return result
    (mark% element                            ; mark the rest of the list
           (rest list)                        
           (cons (equal element (first list)) ; equal for the first element?
                 result))))

(defun mark (element list)
  "return a list with boolean values if element is found in the list"
  (reverse (mark% element list nil)))         : needs to reverse the result

注意

通常不编写这样的递归函数,因为Lisp实际上已经提供了MAPMAPCAR - 那些在一个地方提供了映射功能,并且不需要将递归映射烘焙到每个你自己的功能。

最好使用更高级别的迭代工具,如LOOP:

CL-USER 13 > (loop for e in '(a b a b)
                   collect (equal 'a e))
(T NIL T NIL)

嵌套列表

您可以通过添加第一个元素作为列表的案例测试然后在这种情况下执行某些操作来使上述函数适应嵌套列表...

(defun mark% (element list result) 
  (cond ((null list)
         result)
        ((consp (first list))
         (mark% element
                (rest list)                        
                (cons (mark element (first list))
                      result)))
        (t
         (mark% element
                (rest list)                        
                (cons (equal element (first list))
                      result)))))

<强>调试

使用trace和/或step查看您的代码正在执行的操作。