我需要帮助来理解查找列表深度的 lisp 程序

鲍勃

我需要帮助从理论上理解我的代码。这是我的 lisp 程序:

(defun depth (lst)

(if (or (null lst) (atom lst)) 0 

    (+ 1 (apply 'max (mapcar #'depth lst)))

))

我知道它适用于这个例子:(write (depth '((a (bc) dr ((t))))) -> 3

我只是无法理解我尝试过的 IF 语句的 else 语句。如果您能帮助我,将不胜感激。先感谢您。

核心转储

这是您的代码,稍微重新格式化:

(defun depth (value)
  (if (or (null value) (atom value))
      0
      (+ 1 (apply 'max (mapcar #'depth value)))))

我重命名了lstlist顺便说一下你可以写它value,因为这个名字令人困惑,因为它表明变量总是一个列表,这不是真的。该函数depth可以在任何值上调用:

(depth "hello")
=> 0

(depth 100)
=> 0

then分支ifvalue是 NIL 或 any时进行评估atom由于NIL也是atom,测试表达式可以简化为(atom value)当 value 是一个原子时,深度为零。

其他的分支if时被评估value不是原子,其通过定义atom装置value在这里是一个cons该函数还假定它是一个适当的列表,而不是某个循环列表。

由于value是在该分支的列表,我们可以调用mapcar它:(mapcar #'depth value); 这是函数假定列表正确的地方。它用于计算(depth v)每个vvalue更确切地说,如果value是长名单ñ,那么调用mapcar的计算结果为数字列表(D1 ... Dn),其中Di(depth Vi)为所有i0之间n

所以我们知道这(apply 'max (mapcar ...))(apply 'max depths)一些depths数字列表一般来说:

(apply fn v1 ... vn list)

... 是一种调用由fn表达式表示的函数对象的方法,其中至少包含n元素 ( v1to vn),以及存储在list. 当你引用函数时, as 'max,或者当你写时#'max,你在函数命名空间中通过它的名字来引用一个函数。

将此与调用函数的通常方式进行对比:

(f x y z)

函数名和传递的参数数量是固定的:一旦读取表单,我们就知道有一个f带有 3 个参数的调用。

apply函数是一个内置函数,允许您在列表中的最后一个调用参数中传递其他参数。上面的调用可以写成:

(apply #'f x y z ()) ;; note the empty list as a last argument

这也可以写成:

(apply #'f (list x y z)) ;; all arguments in the last list

唯一的区别可能是运行时效率的问题(对于好的编译器,也许没有区别)。

在您的示例中,您执行以下操作:

(apply max depths)

这与编写(伪代码)相同:

(max d1 d2 d3 ... dn)

...depths列表在哪里(list d1 d2 ... dn)但是我们不能直接把它们全部写出来,因为列表的内容只有在运行时才知道。

因此,调用 apply 计算递归计算的所有深度中的最大深度。请注意,以上是对 的一种有点不正确的使用apply,因为apply不应使用任意大小的列表调用:命名的标准中有一个限制CALL-ARGUMENTS-LIMIT,理论上允许低至 50,即此类列表的最大大小(我们将在下面看到一个替代方案)。

最后,对这个结果depth进行评估(+ 1 ...)换句话说,整个表达式可以概括为:列表的深度为其所有元素的最大深度加1。

使用 reduce

代替apply,您可以使用REDUCEmax列表进行连续计算这是可取的,apply因为:

  • 元素数量没有限制,例如 apply

    (reduce 'max depths) ;; works the same, but more reliably
    
  • 无需构建深度的中间列表,您可以遍历值列表,调用depth并直接使用结果来计算最大值。骨架是:

    (reduce (lambda (max-so-far item) ...)
            value
            :initial-value 0)
    

声明式方法

代替reduceloop宏可以用作更易读的替代方法来表达相同的计算。我还使用typecasewhich 在我看来使意图更清晰:

(defun depth (value)
  (typecase value
    (atom 0)
    (cons (1+ (loop for v in value maximize (depth v))))))

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章