Вопрос Лиспе скобки

этот кусок кода из книги : "Земля Lisp" Первая версия из книги. Когда я читал его, я думал, что есть скобки "(" не обязательно перед "at-loc-p" на 2-й строке и ")" сразу после loc на 3-й строке.

(defun person-at (loc pers per-locs)
       (labels ((at-loc-p (pers)
                 (eq (cadr (assoc pers per-locs)) loc)))
         (remove-if-not #'at-loc-p pers)))

но когда я проверить это ,

(defun person-at (loc pers per-locs)
       (labels (at-loc-p (pers)
                 (eq (cadr (assoc pers per-locs)) loc))
         (remove-if-not #'at-loc-p pers)))

получилось :

требуемые аргументы в AT-LOC-P не список соответствия лямбда (CCL:: FUNCNAME CCL::ЛЯМБДА-ЛИСТ &ТЕЛО CCL:: ЯРЛЫКИ-ФУНКЦИЯ-ТЕЛО).
[Состояние типа CCL:: SIMPLE-PROGRAM-ERROR]

Я не понимаю. Нуждаться в помощи. спасибо.

6 ответов


The LABELS на

(defun person-at (loc pers per-locs)
  (labels ((at-loc-p (pers)
             (eq (cadr (assoc pers per-locs)) loc)))
    (remove-if-not #'at-loc-p pers)))

имеет синтаксис labels ((function-name lambda-list [[local-declaration* | local-documentation]] local-form*)*) declaration* form*, поэтому вам нужно будет предоставить список локальных определений функций для его работы.

поскольку эти определения локальных функций сами заключены в скобки, вам придется передать labels список этой структуры:((fun1 (...) ...) (fun2 (...) ...) ...).

к сожалению, трассировка стека и сообщение об ошибке не очень полезны в обнаружении ошибки здесь, так как сообщение не говорит вам, что проблема с labels, и он также не является самым верхним в трассировке. The 4: (CCL::NX1-LABELS ... будет подсказкой (буфер отладчика на моей локальной машине).

взгляните на документацию для labels на Hyperspec чтобы узнать больше.


в других языках, не шепелявит, скобки обычно используются для группировки операторов и поэтому не являются обязательными во многих случаях. Но в Lisp скобки всегда имеют смысл. Могут не быть дополнительные или факультативные скобки.

чаще всего скобки вокруг выражения означает функция или применение макроса:

(foo 1)

две скобки в начале выражения в таком случае может произойти, например, когда первый элемент выражение-это другое выражение, которое вычисляется для самой функции. Например, представьте функцию make-adder, которая принимает число и возвращает другую функцию с частично применяется также (кстати, это пример карринг):

(defun make-adder (number)
   (lambda (another-number) (+ number another-number)))

мы можем создать переменную функцию increment таким образом, а затем применить его в переменную:

(defvar increment (make-adder 1))
(increment 5)                      ; ==> 6

но мы также можем вызвать его напрямую (хорошо, это не будет работать в Common Lisp, но тот же синтаксис работает в другие шепелявые, называемые "Lisp-1", поэтому я считаю, что стоит упомянуть об этом здесь):

((make-adder 1) 5)                 ; ==> 6

создание двойной скобки в начале. И, конечно, обе скобки обязательны.

и последний случай, который описывает ситуацию, когда макрос языка или пользователя использует список списков для своих целей (вы все еще помните, что программа Lisp сама является списком списков выражений?). Например, defun знает, что его 1-й аргумент должен быть символом, а ее 2-й аргумент должен быть списком. И labels макрос знает, что его 1-й аргумент должен быть список определений, каждое из которых представляет собой список. Это было сделано, чтобы позволить пользователю определять более одной метки за раз:

(labels ((definition-1) (definition-2) ...) 
   (do-this) (do-that) ...)

Итак, вы можете видеть, что каждая скобка означает что-то, и вы не можете отбросить их самостоятельно.


Я думал, что есть скобки "(" не надо

Ну они. Вы не можете просто добавлять и удалять круглые скобки, как вам нравится, и ожидать, что он будет работать больше, чем вы могли бы использовать символ asdklfjhsbf вместо, скажем,defun и ожидать, что это сработает. Вы должны дать ярлыки ((function-name lambda-list forms) ... ), и это всего лишь синтаксис меток; если вы не будете следовать ему, компилятор вызовет ошибку.


скобки являются значимыми и существенными в Lisp. теперь вы можете понять, почему Land of Lisp music video говорит: "Я ем скобки на завтрак... И если моя программа не завершена, я ем парантезы на обед... Они могут выглядеть смешно, но у них есть семантическая сила... Это дает вашим программам много краткости и пунша. скоро вы будете иметь мечты о них тоже!


как сказал @ danlei, должен быть список определений функций в первой части a let/labels/flet. если это один элемент, то вы в конечном итоге с этими избыточными двойными скобками.


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

(dolist (x L) (print x))

в этом случае, например x в первом пантезе не является функцией, которую следует называть проходящей L в качестве аргумента. Другой пример:

(let ((x 10)
      (y 20))
   (print (+ x y)))

в этом случае скобки используются только для группировки и первый элемент (x 10) явно не функция, которая должна применяться, и ее первый элемент x функция либо.

labels работает точно так же, как let и, по-видимому," дополнительная " скобка необходима для группировки в случае более одной функции.

хотя эти особые случаи действительно несколько раздражают, их очень мало, и после написания некоторого количества кода Lisp вы их усвоите, и вы просто получите их правильно, не думая.

они тем не менее асимметрии, которые, например, довольно трудно написать правильный ходок кода, а также часто, когда вы делаете ошибку в этой "области синтаксиса" Lisp, к сожалению, сообщение об ошибке не очень полезно в указывая вам на ошибку.

эта "сложность", конечно, просто ничто по сравнению с другими языками (и давайте не будем начинать обсуждать, насколько ясны сообщения, когда вы делаете ошибку в шаблоне c++; -)).

Я думаю, что это не совсем верно, что синтаксис Lisp "тривиален" или даже просто отсутствует. Синтаксис Lisp присутствует даже если не на уровне символов, а на уровне форм Lisp, и это почти тривиальный с исключением нескольких специальных форм и макросы.