Common lisp 3的倍数之和&;5使用LISP
我试图得到给定数字下3和5的倍数之和。但是代码总是返回到0。有什么问题吗Common lisp 3的倍数之和&;5使用LISP,common-lisp,Common Lisp,我试图得到给定数字下3和5的倍数之和。但是代码总是返回到0。有什么问题吗 (defun modsum2 (n) (let ((summ 0)) (if (>= n 3) (if (or (zerop (mod n 3)) (zerop (mod n 5))) (progn (setq summ (+ n summ)) (modsum2 (1- n))) (modsum2 (1- n)
(defun modsum2 (n)
(let ((summ 0))
(if (>= n 3)
(if (or (zerop (mod n 3)) (zerop (mod n 5)))
(progn (setq summ (+ n summ))
(modsum2 (1- n)))
(modsum2 (1- n)))
(print summ))))
对,现在你把它缩进了。让我们追踪一下:
(defun modsum2 (n)
(let ((summ 0))
(if (>= n 3)
(if (or (zerop (mod n 3)) (zerop (mod n 5)))
(progn (setq summ (+ n summ))
(modsum2 (1- n)))
(modsum2 (1- n)))
(print summ))))
当n
的参数为2
时,可以看到打印0
。由于print
表单也是最后一个表单,因此函数返回其值<代码>(打印0)返回0
。因为返回值在您使用的函数中,所以每次递归调用都会返回它
修复它的一个典型方法是在let
中使用labels
的局部递归函数。然后需要调用该函数。稍后您需要返回summ
* (trace modsum2)
(MODSUM2)
* (modsum2 4)
0: (MODSUM2 4)
1: (MODSUM2 3)
2: (MODSUM2 2)
0 2: MODSUM2 returned 0
1: MODSUM2 returned 0
0: MODSUM2 returned 0
0
对,现在你把它缩进了。让我们追踪一下:
(defun modsum2 (n)
(let ((summ 0))
(if (>= n 3)
(if (or (zerop (mod n 3)) (zerop (mod n 5)))
(progn (setq summ (+ n summ))
(modsum2 (1- n)))
(modsum2 (1- n)))
(print summ))))
当n
的参数为2
时,可以看到打印0
。由于print
表单也是最后一个表单,因此函数返回其值<代码>(打印0)返回0
。因为返回值在您使用的函数中,所以每次递归调用都会返回它
修复它的一个典型方法是在
let
中使用labels
的局部递归函数。然后需要调用该函数。稍后您需要返回summ
您做的工作太多了。只需执行包含排除:
* (trace modsum2)
(MODSUM2)
* (modsum2 4)
0: (MODSUM2 4)
1: (MODSUM2 3)
2: (MODSUM2 2)
0 2: MODSUM2 returned 0
1: MODSUM2 returned 0
0: MODSUM2 returned 0
0
;; your function has some flaws
(defun modsum2 (n)
(let ((summ 0)) ;; in every call, `summ` is put to `0`!
(if (>= n 3) ;; for n = 2, the alternative `(print summ)` is executed
(if (or (zerop (mod n 3)) (zerop (mod n 5)))
(progn (setq summ (+ n summ))
(modsum2 (1- n)))
(modsum2 (1- n)))
(print summ)))) ;; for n = 2 already this is called
;; since summ is set to `0` for this last modsum2 call, it prints 0
;; tail call recursion with inner function
(defun modsum2 (n)
(let ((summ 0))
(labels ((.modsum2 (.n)
(cond ((zerop .n) summ)
((or (zerop (mod .n 3)) (zerop (mod .n 5)))
(setq summ (+ .n summ))
(.modsum2 (1- .n)))
(t (.modsum2 (1- .n))))))
(print (.modsum2 n)))))
;; tail call recursion with optional accumulator for the proper start
(defun modsum2 (n &optional (acc 0))
(cond ((zerop n) acc)
((or (zerop (mod n 3))
(zerop (mod n 5)))
(modsum2 (1- n) (+ acc n)))
(t (modsum2 (1- n) acc))))
;; using loop
(defun modsum2 (n)
(loop for x from 1 to n
when (or (zerop (mod x 3)) (zerop (mod x 5)))
sum x into res
finally (return res)))
;; which is equivalent to (thanks @Rainer Joswig):
(defun modsum2 (n)
(loop for x from 1 to n
when (or (zerop (mod x 3)) (zerop (mod x 5)))
sum x))
;; using reduce or apply
(defun modsum2 (n)
(reduce #'+ (remove-if-not #'(lambda (x) (or (zerop (mod x 3))
(zerop (mod x 5))))
(loop for x from 1 to n))))
;; instead of `reduce`, `apply` would work, too.
要将其扩展到3,5以上,请执行以下操作:
(defun modsum2 (max)
(let ((a (floor max 3))
(b (floor max 5))
(c (floor max 15)))
(/ (- (+ (* 3 a (1+ a))
(* 5 b (1+ b)))
(* 15 c (1+ c)))
2)))
你做的工作太多了。只需执行包含排除:
;; your function has some flaws
(defun modsum2 (n)
(let ((summ 0)) ;; in every call, `summ` is put to `0`!
(if (>= n 3) ;; for n = 2, the alternative `(print summ)` is executed
(if (or (zerop (mod n 3)) (zerop (mod n 5)))
(progn (setq summ (+ n summ))
(modsum2 (1- n)))
(modsum2 (1- n)))
(print summ)))) ;; for n = 2 already this is called
;; since summ is set to `0` for this last modsum2 call, it prints 0
;; tail call recursion with inner function
(defun modsum2 (n)
(let ((summ 0))
(labels ((.modsum2 (.n)
(cond ((zerop .n) summ)
((or (zerop (mod .n 3)) (zerop (mod .n 5)))
(setq summ (+ .n summ))
(.modsum2 (1- .n)))
(t (.modsum2 (1- .n))))))
(print (.modsum2 n)))))
;; tail call recursion with optional accumulator for the proper start
(defun modsum2 (n &optional (acc 0))
(cond ((zerop n) acc)
((or (zerop (mod n 3))
(zerop (mod n 5)))
(modsum2 (1- n) (+ acc n)))
(t (modsum2 (1- n) acc))))
;; using loop
(defun modsum2 (n)
(loop for x from 1 to n
when (or (zerop (mod x 3)) (zerop (mod x 5)))
sum x into res
finally (return res)))
;; which is equivalent to (thanks @Rainer Joswig):
(defun modsum2 (n)
(loop for x from 1 to n
when (or (zerop (mod x 3)) (zerop (mod x 5)))
sum x))
;; using reduce or apply
(defun modsum2 (n)
(reduce #'+ (remove-if-not #'(lambda (x) (or (zerop (mod x 3))
(zerop (mod x 5))))
(loop for x from 1 to n))))
;; instead of `reduce`, `apply` would work, too.
要将其扩展到3,5以上,请执行以下操作:
(defun modsum2 (max)
(let ((a (floor max 3))
(b (floor max 5))
(c (floor max 15)))
(/ (- (+ (* 3 a (1+ a))
(* 5 b (1+ b)))
(* 15 c (1+ c)))
2)))
上周我为euler项目解决了同样的问题。我注意到我的写作方式并没有包含在答案中。把它放在这里,可能会有用
(defun multsum (k max)
"The sum of multiples of `k' below `max'"
(let ((a (floor max k)))
(* k a (1+ a))))
(defun subsequences-reduce (f items)
(unless items (return ()))
(loop for (item . rest) on items
collect (cons 1 item)
nconc (loop for (len . val) in (subsequences-reduce f rest)
collect (cons (1+ len) (funcall f item val)))))
(defun modsum (max &rest nums)
(loop for (len . lcm) in (subsequences-reduce #'lcm nums)
sum (* (if (oddp len) 1 -1) (multsum lcm max))))
(defun modsum2 (max) (modsum max 3 5))
;;查找数字n以下3和5的倍数
;;因为“or”变为t,所以每当它的一个参数返回t时。无需减去15的倍数。
(第2(n)段)
(条件(i n)总和)
(cond((或(zerop(mod i3))
(zerop(mod i 5)))
(setq summ(+SUMMI(()()())))
我上周为欧拉项目解决了同样的问题。我注意到我的写作方式并没有包含在答案中。把它放在这里,可能会有用
(defun multsum (k max)
"The sum of multiples of `k' below `max'"
(let ((a (floor max k)))
(* k a (1+ a))))
(defun subsequences-reduce (f items)
(unless items (return ()))
(loop for (item . rest) on items
collect (cons 1 item)
nconc (loop for (len . val) in (subsequences-reduce f rest)
collect (cons (1+ len) (funcall f item val)))))
(defun modsum (max &rest nums)
(loop for (len . lcm) in (subsequences-reduce #'lcm nums)
sum (* (if (oddp len) 1 -1) (multsum lcm max))))
(defun modsum2 (max) (modsum max 3 5))
;;查找数字n以下3和5的倍数
;;因为“or”变为t,所以每当它的一个参数返回t时。无需减去15的倍数。
(第2(n)段)
(条件(i n)总和)
(cond((或(zerop(mod i3))
(zerop(mod i 5)))
(setq summ(+SUMMI(()()())))
您需要做的第一件事是正确缩进代码,以便缩进基于代码的结构。目前,缩进看起来是随机的。例如,第一个IF和第二个IF缩进相同?第二个不是在第一个里面吗。一旦缩进正确,请查看代码并思考何时调用PRINT函数。要调试此代码,请使用(trace modsum2)
并调用您的函数。我已经更正了缩进,请注意。您已经编辑了代码,并且没有完全缩进。打印语句需要如何缩进?如果您编写更多代码,那么了解编辑器如何缩进Lisp代码将非常有用。您需要做的第一件事是正确缩进代码,以便缩进基于代码的结构。目前,缩进看起来是随机的。例如,第一个IF和第二个IF缩进相同?第二个不是在第一个里面吗。一旦缩进正确,请查看代码并思考何时调用PRINT函数。要调试此代码,请使用(trace modsum2)
并调用您的函数。我已经更正了缩进,请注意。您已经编辑了代码,并且没有完全缩进。打印语句需要如何缩进?如果您编写更多代码,那么了解编辑器如何缩进Lisp代码将非常有用。sum to res finally…
不是必需的<代码>求和…足够了<代码>最后求和到res…不是必需的<代码>总和…足够了