首页 > 解决方案 > LISP 递归三角形

问题描述

我的递归调用似乎不起作用,我试图在给定整数的情况下制作一个三角形,在你们的帮助下,我终于能够在同一行打印字符串,1 行的正确次数。在打印行结束时,我有一个递归调用,它调用三角形来制作另一行,一个字符更短。由于某种原因,这个电话似乎永远无法接通。请在下面找到代码,提前感谢大家的任何帮助,非常感谢!

注意:在旁注中,有什么方法可以停止 Lisp 中的函数,类似于 return 语句?我希望递归在 k = 1 处停止,而不是继续到 k = 0。

(defun newTriangle (k) 
    (cond ((<= k 0) (princ '(Nope))) 
          ((or (= k 1) (= k -1)) (princ 'a)) 
          ((> k 0) (make-string k :initial-element #\a)) 
          (newTriangle (- k 1))))
        
(print (newTriangle 3))

样本输出三角形(3)

aaa 
aa 
a 

样本输出三角形(-3)

aaa 
 aa 
  a

标签: recursionreturnlispcommon-lisp

解决方案


首先,您需要确定它在newTriangle做什么。该调用(print (newTriangle 3))建议newTriangle应该返回一个字符串,然后通过对 的调用打印该字符串print。但是, 的 OP 定义newTriangle既是打印输出,又是返回三角形的单行作为字符串。

递归调用newTriangle永远不会到达,因为在到达此行之前,值的所有可能情况k都已用尽。由于k只能小于零、等于零或大于零,并且由于所有这些情况都在到达递归调用之前进行了测试,因此永远不会到达。另请注意,OP 代码在cond语句的最后部分的语法错误。分支中的第一个表达式cond是一个测试,并且约定在t这里用于一个分支,如果到达该分支将始终被评估。但是,这里不需要这么多情况。

假设newTriangle函数不应该返回一个字符串,而是应该打印一个三角形作为副作用,它应该怎么做?如果输入的数字大于 0,它应该打印一行字符数等于输入数字的行,然后在输入减一的情况下调用自己;否则它应该什么都不做:

(defun print-triangle (k)
  (when (> k 0)
    (princ (make-string k :initial-element #\a))
    (terpri)
    (print-triangle (- k 1))))

命名这个定义是print-triangle为了强调它打印一个三角形作为副作用,因为 kebab-case 在 Lisps 中是惯用的,而 camelCase 不是。请注意,每次print-triangle使用大于零的输入调用时,都会打印一个正确长度的字符串然后打印一个换行符(使用 obscurly-named terpri,它只是将换行符写入当前输出流),然后print-triangle再次调用k减 1 。

示例 REPL 交互:

CL-USER> (print-triangle 3)
aaa
aa
a
NIL

如果目标是返回一个字符串,一种方法是调用一个辅助函数,将结果保存在一个参数中:

(defun new-triangle (k)
  (build-triangle k ""))

(defun build-triangle (k result)
  (if (> k 0)
      (build-triangle (- k 1)
                      (concatenate 'string
                                   result
                                   (make-string k :initial-element #\a)
                                   (string #\newline)))
      result))

在这里,new-triangle接受一个整数参数,并调用build-triangle,在该位置传递整数参数和一个空字符串result。该build-triangle函数的操作与以前大致相同print-triangle,但不是打印行,而是将它们与result包含换行符的字符串连接起来。完成build-triangle后,result字符串返回到new-triangle. 请注意,简单地new-triangle从 REPL 调用会将结果字符串打印为数据(即,带引号);调用print结果new-triangle将把字符串打印为数据,并返回字符串。要查看打印的字符串不带引号,format可以使用;或者你可以使用princ这将打印不带引号的字符串,并返回字符串本身:

CL-USER> (new-triangle 3)
"aaa
aa
a
"

CL-USER> (print (new-triangle 3))

"aaa
aa
a
" 
"aaa
aa
a
"

CL-USER> (format t "~A" (new-triangle 3))
aaa
aa
a
NIL

CL-USER> (princ (new-triangle 3))
aaa
aa
a
"aaa
aa
a
"

推荐阅读