Common Lisp: Функция возвращает имя функции - PullRequest
0 голосов
/ 26 мая 2018

В настоящее время я пытаюсь решить проблему 1 с projecteuler.net.Оценка этой функции возвращает только имя функции.Что я делаю неправильно?

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

Ответы [ 3 ]

0 голосов
/ 26 мая 2018
(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
0 голосов
/ 26 мая 2018

Ошибки

Оценка этой функции возвращает только название функции.

Я не могу повторить это, как вы тестировали свой код, в какой среде?

С 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сопровождаемый корпусом (возможно, пустым).Вы писали:

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

В приведенном выше у вас есть два предложения, одно из которых (пытается) проверяет, делится ли N на 5, а другое проверяет, является ли nSum истинным.

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

Вы добавили круглые скобки вокруг SUM, что означает, что вы хотите вызвать функцию SUM (в настоящее время не определено).Скобки имеют значение в Лиспе.

Исправление ошибок и форматирование

Вот ваш код после исправления предыдущих ошибок и форматирования его в соответствии с правилами стиля 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))))))

Ваш код не вычисляет желаемую функцию.Пожалуйста, прочитайте ответ Гванг-Джин Кима , чтобы узнать, как вычислить его хвост-рекурсивным способом, или ниже для основанного на цикле.

Некоторые дополнительные замечания относительно стиля:

  • Вы не должны использовать snakeCase в Лиспе, вместо этого используйте тире для разделения слов, смиренно известных как lisp-case (и, очевидно,также как kebab-case).

  • Ваши if и cond могут быть объединены вместе.Кроме того, будьте осторожны с отрицательными значениями N.

  • Вы можете сделать (or test1 test2), когда оба теста приводят к выполнению одного и того же кода.Это позволяет избежать дублирования кода.

Альтернативная реализация

Использование LOOP:

(defun euler-1 (n)
  (loop
    for i below n
    when (or (zerop (mod i 3))
             (zerop (mod i 5)))
      sum i))
0 голосов
/ 26 мая 2018

Вы должны использовать eq для проверки на равенство (или, возможно, равно ; для целых чисел это то же самое), или = для сравнения чисел.И в Common Lisp нет инфиксного оператора.Так что ( n = 0) должно быть что-то вроде (eq n 0) или (= n 0) и т. Д.

...