Ошибка переменной v Lisp при оценке функции - PullRequest
3 голосов
/ 01 сентября 2009

Я пытаюсь выучить Лисп (на самом деле elisp), и я попытался написать следующую функцию в качестве упражнения Project Euler Задача 2

(defun sumfib (n fn1 fn2 sum)
  "Calculate Fibonacci numbers up to 4,000,000 and sum all the even ones"
  (if (< 4000000 (+ fn1 fn2))
      sum
    (if (equal n 3)
        (sumfib 1 (+ fn1 fn2) fn1 (+ sum (+fn1 fn2)))
      (sumfib (+ n 1) (+ fn1 fn2) fn1 sum)))

Когда я оцениваю это, я получаю следующую ошибку:

Debugger entered--Lisp error: (void-variable fn1)
  (+ fn1 fn2)
  (< 4000000 (+ fn1 fn2))
...

Почему он не распознает fn1? Если я попытаюсь поставить (+ fn1 fn2) перед «если», он не будет там жаловаться, так почему же здесь ошибка?

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

Ответы [ 2 ]

4 голосов
/ 02 сентября 2009
  1. Вам понадобится дополнительная закрывающая скобка в конце вашей функции.
  2. Вам нужен пробел в первом предложении второго, если: (+fn1 fn2) должно быть (+ fn1 fn2). В противном случае ELisp читает его как передачу fn2 в функцию с именем +fn1.

Пара других стилевых проблем:

  1. A cond намного легче читать, чем вложенные ifs, особенно с использованием стиля отступов ELisp.
  2. = - это обычный предикат, используемый для сравнения чисел, а не equal. Хотя equal будет работать, для читателя это выглядит забавно. (По крайней мере, во всех остальных Лиспах, которые я знаю, я могу ошибаться, потому что я тоже не знаю ELisp.)

Вот как я бы реструктурировал функцию.

(defun sumfib (n fn1 fn2 sum)
  "Calculate Fibonacci numbers up to 4,000,000 and sum all the even ones"
  (cond 
    ((< 4000000 (+ fn1 fn2)) sum)
    ((= n 3) (sumfib 1 (+ fn1 fn2) fn1 (+ sum (+ fn1 fn2))))
    (t (sumfib (1+ n) (+ fn1 fn2) fn1 sum))))

Я запустил его, и он возвращает ответ, но я не знаю, правильно ли это в соответствии со спецификацией проекта Эйлера.

2 голосов
/ 01 сентября 2009

Не уверен, решит ли это вашу проблему (у меня нет под рукой переводчика elisp), но вам не хватает подходящего члена. В конце первого оператора «if» должен быть один после «sum».

  (if (< 4000000 (+ fn1 fn2))
      sum)

вместо:

 (if (< 4000000 (+ fn1 fn2))
      sum

Я также думаю, что там могут быть и другие проблемы.

...