#lisp #common-lisp
#lisp #common-lisp
Вопрос:
Только начал изучать lisp. Я понятия не имею, почему я получаю эти ошибки или даже что они означают. Я просто пытаюсь закодировать приближение числа pi, используя ряд Грегори-Лейбница, вот код.
(defun gl (n)
(defparameter x 0) ;init variable to hold our runnning sum
(loop for y from 0 to n ;number of iterations, starting from 0 to desired n
(if (= y 0) ;if n is 0 then we just want 4
(defparameter w 4))
(if (> y 0) ;else, 4*(-1^y)/((2 * y) 1)
(defparameter w (* 4 (/ (exp -1 y) ( (* 2 y) 1)))))
( x w)) ;add to our running sum
(write x)) ;once loop is over, print x.
Я пытался использовать setq, defvar, let и т.д. Вместо defparameter, Но я все еще получаю «Необъявленную свободную переменную X».
Я также получаю ошибку «Неиспользуемая лексическая переменная N», хотя я использую ее для своего цикла, что тоже странно.
Как я могу это исправить и почему это происходит? Спасибо!
Комментарии:
1. Не используйте
defparameter
внутриdefun
. Вам следует проверить Hyperspec или какую-нибудь вводную книгу (рекомендации см. в разделе info), чтобы найти идиоматический способ определения локальных переменных с помощьюlet
или внутриloop
.
Ответ №1:
Вот код после того, как Emacs автоматически сделал отступ:
(defun gl (n)
(defparameter x 0)
(loop for y from 0 to n
(if (= y 0)
(defparameter w 4))
(if (> y 0)
(defparameter w (* 4 (/ (exp -1 y) ( (* 2 y) 1)))))
( x w))
(write x))
Компиляция следующего кода с использованием SBCL выдает одну ошибку и два предупреждения.
В одном предупреждении говорится, что x
не определено. Вы не должны вызывать defparameter
из своей функции, поскольку defvar
и defparameter
используются для объявления динамических переменных и установки их значения в глобальной области видимости. Предпочитаю иметь привязки let или, поскольку вы уже используете цикл, with
предложение. Если вы хотите изменить привязку, используйте setf
.
Ошибки возникают из-за неправильного макрорасширения LOOP
. Для SBCL это означает, что код обрабатывается как мертвый код для остальной части компиляции функции; это объясняет, почему n
кажется, что он не используется, о чем и второе предупреждение.
Осталось выполнить различные исправления:
- Используйте функцию
EXPT
, а неEXP
. - Вызов
( x w)
только вычисляет значение, но не изменяетx
, результат бесполезен. - Предпочитаю использовать
if
как выражение, подобно троичному оператору в других языках, в вашем случае код можно упростить - Добавить ее можно с помощью функции
1
(это название функции, а не специальный синтаксис для добавления констант) write
Операция редко требуется, особенно если вы вычисляете математическую формулу; просто верните значение, и REPL напечатает его автоматически.
Небольшие исправления, которые заставят ваш код работать:
(defun gl (n)
(let ((x 0))
(loop
for y from 0 to n
for w = (if (= y 0)
4
(* 4 (/ (expt -1 y) ( (* 2 y) 1))))
do (setf x ( x w)))
(write x)))
Я бы лично избавился от x
and w
и использовал SUM
предложение цикла.
(defun gl (n)
(loop
for y from 0 to n
sum (if (zerop y)
4
(* 4 (/ (expt -1 y)
(1 (* 2 y)))))))
Комментарии:
1. Вау! Я понятия не имел, что делаю так много вещей неправильно, лол. Думаю, я привык владеть Python и c вручную. Спасибо за помощь!
2. @Matt это в основном зависит от того, насколько вы знакомы с ним, вы, вероятно, легко освоитесь с CL, который в некоторых отношениях проще, чем C и Python (например, меньше угловых случаев).
3. Вы говорите, что Python держит руку на пульсе? Мы можем скомпилировать
def foo(x): ... return y
в Python 3 без предупреждения, котороеx
не используется, или предупреждения, котороеy
не определено. Появляется.pyc
файл, определяющий нерабочую скомпилированную функцию.