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参数列表。