Common Lisp:Function返回函数名称

时间:2018-05-26 03:49:36

标签: lisp common-lisp

我目前正在尝试从projecteuler.net解决问题1。对此函数的评估仅返回函数的名称。我究竟做错了什么?

{"id":"123","title":"aaa","url":"aaaa","visit":"1"},{"id":"456","title":"aaa","url":"aaaa","visit":"0"},{"id":"789","title":"aaa","url":"aaaa","visit":"0"},

3 个答案:

答案 0 :(得分:4)

错误

  

评估此功能仅返回功能的名称。

我无法复制这一点,您是如何在哪个环境下测试代码的?

使用SBCL,这是评估defun表单打印的内容:

; in: DEFUN NSUM
;     (N = 0)
; 
; caught WARNING:
;   undefined variable: =

=符号用于评估为变量的位置。如果你想调用绑定到=的函数,即(function =),也可以写#'=,那么你必须写(= ... ...)

; caught STYLE-WARNING:
;   undefined function: N

由于您在正常评估规则下编写了(N = 0),即N作为表单的第一个元素,因此代码会尝试调用函数N。在您的情况下,您没有定义此类功能。

;     (COND ((MOD N 5) = 0) (NSUM (- N 1) (+ SUM N)) ((MOD N 3) = 0)
;           (NSUM (- N 1) (+ SUM N)) (NSUM (- N 1) (+ SUM N)))
; --> IF 
; ==>
;   (IF NSUM
;       (PROGN (- N 1) (+ SUM N))
;       (IF (MOD N 3)
;           (PROGN = 0)
;           (IF NSUM
;               (PROGN (- N 1) (+ SUM N))
;               (IF NSUM
;                   (PROGN # #)
;                   NIL))))
; 
; caught WARNING:
;   undefined variable: NSUM

您正在编写cond子句,在该上下文中,每个子句应该是一个匹配(test . body)的列表,即一个test表达式,后跟case主体(可能为空)。你写道:

(cond (  (mod n 5) =  0) ( nSum ( - n 1) (+ sum n)) ...)

在上面,你有两个子句,一个(试图)测试N是否可被5整除,另一个测试nSum是否为真。

;     (SUM)
; 
; caught STYLE-WARNING:
;   undefined function: SUM

您在SUM周围添加了括号,这意味着您要调用函数SUM(当前未定义)。括号在Lisp中很重要。

修复错误和格式

以下是修复之前错误并根据Lisp样式规则对其进行格式化的代码:

(defun nSum (n sum) 
  (if (= n 0)
      sum
      (cond
        ((= 0 (mod n 5)) (nSum (- n 1) (+ sum n)))
        ((= 0 (mod n 3)) (nSum (- n 1) (+ sum n)))
        (t (nSum (- n 1) (+ sum n))))))

您的代码无法计算所需的功能。请阅读Gwang-Jin Kim's answer以了解如何以尾递归的方式计算它,或者在下面找到基于循环的方法。

另外一些评论w.r.t.式:

  • 你不应该在Lisp中使用 snakeCase ,而是使用破折号来分隔单词,谦卑地称为 lisp-case (显然,也是{ {1}})。

  • 您的kebab-caseif可以合并在一起。另外,请注意负面cond

  • 当两个测试导致执行相同的代码时,您可以执行N。这可以避免代码重复。

替代实施

使用LOOP

(or test1 test2)

答案 1 :(得分:2)

(defun nsum (n)
  (labels ((inner-nsum (m sum)     ; using `labels` define local recursive function
             (cond ((= m 0) sum)   
                   ((= (mod m 3) 0) (inner-nsum (- m 1) (+ m sum)))
                   ((= (mod m 5) 0) (inner-nsum (- m 1) (+ m sum)))
                   (t (inner-nsum (- m 1) sum))))) 
    (inner-nsum (- n 1) 0)))       ; call it with n decremented by 1 
                                   ; to implement "below n"
(nsum 10)   ;; 23      ; test successful!
(nsum 1000) ;; 233168

答案 2 :(得分:0)

您应该使用eq进行相等性测试(或者equal;对于整数它是相同的),或=用于比较数字。并且 Common Lisp中没有中缀运算符。因此( n = 0)应该类似于(eq n 0)(= n 0)等。