lisp - 解释一下我的 LISP 代码

标签 lisp

我是 LISP 的新手,我想了解递归。

我所知道的是递归需要一个停止条件。在我下面的代码中,你能向我解释一下为什么 (equal x 0) 1 是我的停止条件,因为 fact(- X 1) 可以像我的第二个条件一样无限期地继续,我已将 t 我的 cond 的第二行设置为 t ,这意味着它应该继续。

但是当我运行该程序时,它运行良好。下面是我的代码(偶然发现的)

(defun fact(x)
    (cond
        ((equal x 0) 1)
        (t (*(fact(- x 1)) x)) 
    )
)

最佳答案

cond 表达式有多个子句。每个子句的形式都是 (expr1 expr2)。如果 expr1 的计算结果为真,则 expr2 被计算,这就是 cond` 的返回值。没有评估其他条款。

因此,一旦 x 变为 0cond 的第一个子句的计算结果为 true 并且调用 fact返回 1

cond 的另一个子句的第一个表达式 t 根据定义为真;因此,如果不使用第一个子句,它总是使用第二个子句。 (带有 tcond 子句就像其他语言中“if”语句中的“else”。)

此函数是递归的,如果您使用参数 2 调用它,它会检查 2 == 0,如果不是,则它会用 1 递归调用自身返回的值乘以 2。因为 1 != 0 它将返回 1 的值乘以用 0 递归调用自身的值。由于 0 确实等于 0 它只返回 1,它使用一层返回 1,然后在该递归的顶层使用返回 1 2.

Common Lisp 有一个函数 trace这会让你看到你的函数何时被调用以及参数是什么。通常每个递归调用都会缩进,因此您可以看到如下内容:

(fact 2)
    (fact 1)
       (fact 0)

这有助于理解这个函数。

(如评论中所述 - 此函数不捕获负输入的情况 - 但这是错误处理并且可以轻松修复)。

关于lisp - 解释一下我的 LISP 代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38483063/

相关文章:

emacs - 将光标定位在初始化重新绑定(bind)宏中

lisp - 为什么需要在mapcar里面使用symbol-value来赋值?

graphics - 使用graphics-draw-line定义过程

macros - Clojure 宏在调用时抛出 "CompilerException java.lang.IllegalStateException: Var clojure.core/unquote is unbound"

javascript - 如何编写能够正确缩进方案代码的 JavaScript 函数?

string - 在 'eval' 中运行的 Python 字符串

emacs - 为什么人们说 "emacs is good for writing lisp program because it' 是用 emacs lisp 编写的”?

python - 在某些 lisp 语言上,这个 Python 散列写入/访问代码的等效项是什么?

random - 一个 Common Lisp 程序错误

variables - 如何在clojure宏中绑定(bind)var的名称和值?