我不知道这个功能应该做什么

时间:2014-01-13 22:09:59

标签: lisp common-lisp

我这里有一个我需要修改的函数,这样我就可以避免(f (car l))的双递归调用。首先,我无法弄清楚它显示的是什么.. 如果我通过(f '((3 4) 5 6)),则会显示CAR: 3 is not a list 任何人都可以帮助我理解并修改它吗?

(DEFUN F (L)
   (COND
      ((NULL L) 0)
      ((> (f (car l)) 2) (+ (car l) (f (cdr l))))
      (T (f (CAR L)))
))

1 个答案:

答案 0 :(得分:1)

您可以通过查看输入对输入的作用以及通过查看每个案例返回的内容来确定此函数应该接受的输入。有三种情况:

案例1

((NULL L) 0)

在这种情况下,L可以是nil,并且会返回0,这是一个数字。

案例2

((> (f (car l)) 2) (+ (car l) (f (cdr l))))

在这种情况下,我们会在car上同时调用cdrl,因此l最好是cons。我们还将(f (car l))2进行了比较,因此f必须返回一个数字,至少对于(car l)类型是什么。由于我们使用+致电(car l)(car l)必须是一个数字。所以f必须在给定数字时返回一个数字。现在,我们也使用+调用(f (cdr l)),因此无论(cdr l)类型有什么,f最好还为它返回一个数字。

案例3

(T (f (CAR L)))

这并没有给我们带来很多限制。这只是说如果我们没有前两个案例中的任何一个,那么我们返回(f (car l))。由于检查第二个案例没有失败,并且因为我们正在调用(car l),所以l在这种情况下仍然必须是cons

那么f是什么?

嗯,它仍然不能立即清楚f是什么,但我们可以把它写成分段函数,也许这会有所帮助。它需要一个列表,它可以是空列表,也可以是具有第一个和其余部分的缺点。

f []   = 0
f x:xs = if (f x) > 2
         then x + (f xs)
         else (f x)

要对其进行修改以便您只调用(f (car l))很容易,但由于我们知道输入需要是一个列表,因此我将使用firstrest建议,而不是carcdr

(defun f (list)
    (if (endp list)
        0
        (let ((tmp (f (first list))))
          (if (> tmp 2)
              (+ (first list) 
                 (f (rest list)))
              tmp))))

让我们尝试介绍一些可能的输入并尝试覆盖不同的代码分支。我们称之为 的输入是什么?好吧,我们可以用()

来调用它
CL-USER> (f '())
0

负责第一个then分支。现在如果我们想要击中第二个呢?然后我们需要传递一些不是空列表的东西,所以看起来像(? . ??). Now the first thing that has to happen is a recursive call to(f(第一个列表)). The only way that this is going to work is if(第一个列表)is also a list that we can pass to f and get a value back. Then(第一个列表)`必须是空列表或其他合适的列表。所以我们可以打电话:

CL-USER> (f '(() a b c))
0

一般情况下,我们可以使用f()调用list(first (first (first ... (first list))))()。我们可以用其他东西来称呼它吗?它似乎不是这样。所以现在我们知道f的可接受输入是什么:

input ::= ()
        | (input . anything)

,输出将始终为0