Lisp递归平方使用一个变量
这是一个正在尝试的代码Lisp递归平方使用一个变量,lisp,common-lisp,Lisp,Common Lisp,这是一个正在尝试的代码 (defun f (a n) (if (zerop n) 1 (* a (f a (- n 1))))) (f3)应返回27,(f4)应返回256 我尝试使用两个变量,但这是违反规则的 是否可以使用递归仅使用一个变量 谢谢你的建议,我不知道CL,但我知道Clojure和其他使用递归的语言 如果递归函数有一个作为累加器的参数,但仅在第一次调用时设置,典型的解决方法是在另一个函数中包装f。有两种方法(基本相同): (defun g (
(defun f (a n)
(if (zerop n)
1
(* a (f a (- n 1)))))
(f3)
应返回27,(f4)
应返回256
我尝试使用两个变量,但这是违反规则的
是否可以使用递归仅使用一个变量
谢谢你的建议,我不知道CL,但我知道Clojure和其他使用递归的语言 如果递归函数有一个作为累加器的参数,但仅在第一次调用时设置,典型的解决方法是在另一个函数中包装
f
。有两种方法(基本相同):
(defun g (a n)
(if (zerop n)
1
(* a (g a (- n 1)))))
(defun f (n)
; I'm assuming you want the initial value of "a" to be 1
(g 1 n))
或者更简洁地说:
(defun f (n)
(let (g (fn (n)
(if (zerop n)
1
(* a (g a (- n 1))))))))
; Instead of f being recursive, f calls g, which is recursive
(g 1 n))
请原谅任何语法错误。是的,这是可能的:
(defun f (n)
(cond
((numberp n)
(f (cons n n)))
((zerop (car n))
1)
(t
(* (cdr n)
(f (cons (1- (car n))
(cdr n)))))))
诀窍在于,您可以在单个变量中存储任何数据结构(包括一对数字)
或者,您可以使用标准库中的帮助程序:
(defun f (n)
(apply #'*
(loop repeat n collect n)))
但这并不使用递归。或者简单地说:
(defun f (n)
(expt n n))
使用额外的变量倒计时是明智的选择,但您不需要仅为此更改一个数值参数输入的约定。您可以制作一个帮助器来执行此操作:
(defun exptnn (n)
"Get the (expt n n)"
(check-type n integer)
(labels ((helper (acc count)
(if (zerop count)
acc
(helper (* acc n) (1- count)))))
(if (< n 0)
(/ 1 (helper 1 (- n)))
(helper 1 n))))
(defun exptn(n)
“获取(expt n)”
(检查类型n整数)
(标签((辅助对象(acc计数))
(如果(零位计数)
行政协调会
(助手(*附件n)(1-计数()()))
(如果(
现在,不需要任何助手,只需要一个参数就可以解决问题,因为已经有解决方案了,但我必须说,这就像在没有乐趣的情况下编程一样 这是一种不使用具有多个参数的函数的解决方案(除了
=
,+
,*
,logand
,ash
;还请注意logand
和ash
始终将常量作为第二个参数,以便它们也可以作为一元函数实现)
CL-USER 15 > (defun f (n)
(labels ((g (m)
(if (zerop m)
1
(* n (g (1- m))))))
(g n)))
F
CL-USER 16 > (f 0)
1
CL-USER 17 > (f 1)
1
CL-USER 18 > (f 2)
4
CL-USER 19 > (f 3)
27
CL-USER 20 > (f 4)
256
CL-USER 21 > (loop for i below 10 collect (f i))
(1 1 4 27 256 3125 46656 823543 16777216 387420489)
其思想是使用奇偶位在单个整数中“隐藏”明显递归方法所需的两个参数
(defun pair (n)
(if (= n 0)
0
(+ (* 3 (logand n 1))
(ash (pair (ash n -1)) 2))))
(defun pair-first (p)
(if (= p 0)
0
(+ (logand p 1)
(ash (pair-first (ash p -2)) 1))))
(defun pair-second (p)
(pair-first (ash p -1)))
(defun subsec (p)
(if (= 2 (logand p 2))
(- p 2)
(+ (logand p 1) 2 (ash (subsec (ash p -2)) 2))))
(defun pairpow (p)
(if (= (pair-second p) 1)
(pair-first p)
(* (pair-first p)
(pairpow (subsec p)))))
(defun f (n)
(pairpow (pair n)))
当然,没有合理的实际用途;但这的确是一个有趣的练习。谢谢你的回答。关于语法,
(let((g(fn(n)…))…)
是在CL()@coredump标签中编写的(labels((g(n)…))…)
?我从来没有想到过。等我上笔记本电脑的时候我会修好的。谢谢你的提醒。是的。令人惊讶的是,历史原因很有趣,甚至在上下文中也是有意义的:Clojure也需要上下文:多个arity(defn foo([a]a)([]0))
,数组[ab]
与绑定[ab]
@Carcigenicate,因为标签
允许定义多个相互递归的函数。如果要在列表中乘法,最好使用REDUCE而不是APPLY。APPLY可能只支持最大长度的CALL-LIMIT参数列表。