Common lisp 函数内变量的作用域
我写了一个函数,它返回小于20的数n的素因式分解。该函数使用let创建一个指数列表,并在发现n可被素数整除时增加这些指数 在我的Lisp解释器(gcl和clisp)中,当我调用下面的函数一次时,我得到了正确的因式分解,但当我第二次调用它时,我得到了第一个和第二个函数的因式分解之和-但Common lisp 函数内变量的作用域,common-lisp,literals,Common Lisp,Literals,我写了一个函数,它返回小于20的数n的素因式分解。该函数使用let创建一个指数列表,并在发现n可被素数整除时增加这些指数 在我的Lisp解释器(gcl和clisp)中,当我调用下面的函数一次时,我得到了正确的因式分解,但当我第二次调用它时,我得到了第一个和第二个函数的因式分解之和-但指数的范围不限于let内部吗!?为什么不为指数重新分配值'(0 0 0 0 0 0 0 0 0 0)?如何重新编写此函数,使其能够承受多次调用 (setf primes '(2 3 5 7 11 13 17 19))
指数的范围不限于let内部吗!?为什么不为指数重新分配值'(0 0 0 0 0 0 0 0 0 0)
?如何重新编写此函数,使其能够承受多次调用
(setf primes '(2 3 5 7 11 13 17 19))
(defun factorize (n)
(let ((exponents '(0 0 0 0 0 0 0 0)))
(loop for i from 0 to (- (length primes) 1) do
(loop while (and (= (mod n (nth i primes)) 0)
(not (= n 1))) do
(incf (nth i exponents))
(setf n (/ n (nth i primes)))))
(return-from factorize exponents)))
输出:
>(factorize 10) ;; first time
(1 0 1 0 0 0 0 0) ;; 2^1*5*1 = 10, correct
>(factorize 10)
(2 0 2 0 0 0 0 0) ;; wrong
>(factorize 10)
(3 0 3 0 0 0 0 0)
列表“(0 0 0 0 0 0 0)存储为文本,修改文本是未定义的行为。你应该使用
(let ((exponents (copy-list '(0 0 0 0 0 0 0 0))))
在每次需要时复制文本,或者
(let ((exponents (list 0 0 0 0 0 0 0 0)))
顺便说一句,使用
(defparameter *primes* '(2 3 5 7 11 13 17 19))
而不是在顶层设置f
。请注意,*
符号是一种惯例,表示这是一个特殊变量。列表(0 0 0 0 0 0 0 0 0)存储为文本,修改文本是未定义的行为。你应该使用
(let ((exponents (copy-list '(0 0 0 0 0 0 0 0))))
在每次需要时复制文本,或者
(let ((exponents (list 0 0 0 0 0 0 0 0)))
顺便说一句,使用
(defparameter *primes* '(2 3 5 7 11 13 17 19))
而不是在顶层设置f
。请注意,*
符号是一种惯例,表示这是一个特殊变量。列表(0 0 0 0 0 0 0 0 0)存储为文本,修改文本是未定义的行为。你应该使用
(let ((exponents (copy-list '(0 0 0 0 0 0 0 0))))
在每次需要时复制文本,或者
(let ((exponents (list 0 0 0 0 0 0 0 0)))
顺便说一句,使用
(defparameter *primes* '(2 3 5 7 11 13 17 19))
而不是在顶层设置f
。请注意,*
符号是一种惯例,表示这是一个特殊变量。列表(0 0 0 0 0 0 0 0 0)存储为文本,修改文本是未定义的行为。你应该使用
(let ((exponents (copy-list '(0 0 0 0 0 0 0 0))))
在每次需要时复制文本,或者
(let ((exponents (list 0 0 0 0 0 0 0 0)))
顺便说一句,使用
(defparameter *primes* '(2 3 5 7 11 13 17 19))
而不是在顶层设置f。请注意
*
符号,这是一种惯例,表示这是一个特殊变量。这只是另一个有趣的基于循环的解决方案,不涉及对列表的随机访问(效率相当低)。这还利用了,它返回一个商和一个余数作为多个值(您可以使用循环收集和分解)。由于您可以迭代素数,因此您只需收集指数即可:
(defparameter *primes* '(2 3 5 7 11 13 17 19))
(defun factorize (n)
(loop
for p in *primes*
collect (loop
for (quotient remainder) = (multiple-value-list (truncate n p))
while (zerop remainder)
count (setf n quotient))))
当然,一旦你遍历一个列表并为每个值收集一个值,你就可以使用mapcar了。这是另一个有趣的基于循环的解决方案,不涉及对列表的随机访问(这是相当低效的)。这还利用了,它返回一个商和一个余数作为多个值(您可以使用循环来收集和分解这些数据。由于您可以迭代素数,因此您只需收集指数即可:
(defparameter *primes* '(2 3 5 7 11 13 17 19))
(defun factorize (n)
(loop
for p in *primes*
collect (loop
for (quotient remainder) = (multiple-value-list (truncate n p))
while (zerop remainder)
count (setf n quotient))))
当然,一旦你遍历一个列表并为每个值收集一个值,你就可以使用mapcar了。这是另一个有趣的基于循环的解决方案,不涉及对列表的随机访问(这是相当低效的)。这还利用了,它返回一个商和一个余数作为多个值(您可以使用循环来收集和分解这些数据。由于您可以迭代素数,因此您只需收集指数即可:
(defparameter *primes* '(2 3 5 7 11 13 17 19))
(defun factorize (n)
(loop
for p in *primes*
collect (loop
for (quotient remainder) = (multiple-value-list (truncate n p))
while (zerop remainder)
count (setf n quotient))))
当然,一旦你遍历一个列表并为每个值收集一个值,你就可以使用mapcar了。这是另一个有趣的基于循环的解决方案,不涉及对列表的随机访问(这是相当低效的)。这还利用了,它返回一个商和一个余数作为多个值(您可以使用循环来收集和分解这些数据。由于您可以迭代素数,因此您只需收集指数即可:
(defparameter *primes* '(2 3 5 7 11 13 17 19))
(defun factorize (n)
(loop
for p in *primes*
collect (loop
for (quotient remainder) = (multiple-value-list (truncate n p))
while (zerop remainder)
count (setf n quotient))))
当然,一旦你遍历一个列表并为每个值收集一个值,你就可以使用mapcar。更好,因为指数的长度应该与素数的数量相同
(mapcar(经常为0)*primes*)
。不要在这里使用从返回。是的,循环构造(返回指数)
会更清晰。除此之外,指数列表也可以是(循环指数=…
。更好的是,因为指数的长度应该与素数(mapcar(经常为0)*primes*)
)相同。并且不要在这里使用从
返回。是的,循环结构最终是(返回指数)
会更清晰。除此之外,指数列表也可以是(循环指数=…
。更好的是,因为指数的长度应该与素数(mapcar(经常为0)*primes*)
)相同。并且不要在这里使用从
返回。是的,循环结构最终是(返回指数)
会更清晰。除此之外,指数列表也可以是(循环指数=…
。更好的是,因为指数的长度应该与素数(mapcar(经常为0)*primes*)
)相同。并且不要在这里使用从
返回。是的,循环结构最终是(返回指数)
会更清晰。除此之外,指数列表可能是(loop with exponents=…
。引用的数据是文字数据。如果您熟悉C,您可能会从代码中的文字字符数组中识别该行为。读取器会为您创建一个零的文字列表,该列表存储在编译代码中,因此您只有一个列表,并且它在函数的所有运行之间共享。Quoted数据是文字数据