LISP 递归三角形

LISP Recursive Triangle

我的递归调用似乎不起作用,我正在尝试给定一个整数来制作一个三角形,在你们的帮助下,我终于能够在同一行打印出正确数量的字符串1 行的次数。在打印该行的最后,我有一个递归调用,它调用 triangle 来生成另一行,一个字符更短。由于某种原因,此电话似乎永远无法接通。请在下面找到代码,在此先感谢大家的帮助,非常感谢!

注意:附带说明一下,有什么方法可以停止 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

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

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

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

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

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

示例 REPL 交互:

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

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

(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 字符串被 return 编辑为 new-triangle。请注意,只需从 REPL 调用 new-triangle 就会将结果字符串 打印为数据 (即,带引号);在 new-triangle 的结果上调用 print 会将字符串打印为数据,return 会打印字符串。要查看不带引号打印的字符串,可以使用format;或者您可以使用 princ 打印不带引号的字符串,而 return 打印字符串本身:

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
"