尝试在Lisp中递归打印三角形 [英] Trying to print a triangle recursively in lisp

查看:125
本文介绍了尝试在Lisp中递归打印三角形的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

尝试以Lisp递归方式打印三角形。我溢出了,但我不知道从哪里来。请记住,我是Lisp编程的新手。

Trying to print a triangle recursively in lisp. I get an overflow but I don't know from where. Mind you I am new to Lisp programming.

(defun triangle (n)
    (if (not (oddp n))(progn 
        (print "This is not an odd integer")
        (return-from triangle n)))   
    (if (< n 1) '())
            (setf lst (cons (car(list n)) (triangle (- n 2))))
    (print lst))

(三角形7)

推荐答案

让我们回顾一下代码的某些部分。

Let's review some parts of your code.

(if (not (oddp n)) (progn (print ...) (return-from ...)))

如果您的 if 仅具有一个分支,则在或<$ c时考虑使用 $ c>除非,尤其是
(如果您在子表单中放入 progn )。例如,通过将
切换为 时,可以摆脱 progn

When you have an if with only one branch, think about using when or unless, especially if you put a progn in the subform. For example, you can get rid of the progn by switching to a when:

(when (not (oddp n))
  (print ...)
  (return-from ...))

(当(不是...)时)表达式与相同(除非...)

(unless (oddp n)
  ...)

在这里打印错误消息,然后从函数返回。
Common Lisp具有例外,这些例外针对那些用例。
通常会调用(错误不是奇数整数:〜d n)
,但是在这里您可以依赖断言,而
将整个支票替换为:

Here, you print an error message, and return from the function. Common Lisp has exceptions, which are made for those use cases. You would typically call (error "Not an odd integer: ~d" n), but here you can rely on the default behaviour of assert, and replace the whole check by:

(assert (oddp n))

如果尝试使用2,则会收到一条错误消息与此类似:

If you try it with 2, you will obtain an error with a message similar to this:

The assertion (ODDP N) failed with N = 2.

足够进行测试。

然后,您具有以下表达式:

Then, you have the following expression:

(cons (car (list n)) (triangle (- n 2)))

当您编写(列表e1 e2 .. zh)时,就好像您写道:

When you write (list e1 e2 .. en), it is as-if you wrote:

(cons e1 (cons e2 (... (cons en nil))))

在您的情况下,这意味着(列表n)是相同的

In your case, that means that (list n) is the same as:

(cons n nil)

但是自从您执行以下操作后:

But since you then do the following:

(car (cons n nil))

实际上,您只是分配一个单元并丢弃它只是为了访问 n
整个表达式可以替换为 n

You are just in fact allocating a cell and discarding it just to access n. The whole expression can be replaced by n.

第三,您还可以使用<$ c $ lst 上的c> setf ,其中 lst 是未定义的变量。
在大多数实现中(但实际上未指定此行为),这会将全局绑定
设置为 lst ,这是一个不好的做法函数内部的全局变量。
您可以使用 let 代替:

Third, you also uses setf on lst, where lst is an undefined variable. On most implementations (but really this behaviour is unspecified), that would set the global binding for lst, and it is a bad practice to set global variables from within functions. You could use a let instead:

(let ((lst (cons n (triangle (- n 2)))))
  (print lst))

但是该变量仅使用一次,您也可以内联它:

But the variable is used only once, you may as well inline it:

(print (cons n (triangle (- n 2))))

最后,您有:

(defun triangle (n)
  (assert (oddp n))
  (if (< n 1)
      ()
      (print (cons n (triangle (- n 2))))))

这是样式问题,但请记住,在其分支之一中返回 nil if 通常可以当或除非时,用代替
(这里除非)。有些人不喜欢这样,宁愿不依赖和<$ c $时 nil 的返回值c>除非
无论如何,让我们对其进行测试:

This is a mattery of style, but remember that the if that returns nil in one of its branch can usually be replaced by when or unless (here unless). Some people don't like that and prefer to not rely on the nil return value of when and unless. Anyway, let's test it:

(triangle 7)

这给出了

(1)
(3 1)
(5 3 1)
(7 5 3 1)

请注意列表如何向后移动。
您可以尝试解决问题的一种方法是将(print ...)替换为(print(reverse ...)) ),但这是行不通的。

Notice how the lists are backwards. One way you could try to solve the problem is by replacing (print ...) by (print (reverse ...)), but that won't work. Can you see why?

相反,让我们向后构建列表,需要从1开始向上计数,直到达到 n

Instead, let's build the list backwards, which requires to count up from 1, until we reach n:

(defun triangle (n &optional (c 1))
  (assert (oddp n))
  (when (<= c n)
    (print
      (cons c (triangle n (+ c 2))))))

由于第二个参数是可选的,因此可以像以前一样调用它:

Since the second parameter is optional, we can call it as before:

(triangle 7)

现在,输出为:

(7)
(5 7)
(3 5 7)
(1 3 5 7)

这篇关于尝试在Lisp中递归打印三角形的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆