Вопрос о скобках Lisp

Этот фрагмент кода взят из книги: "Land Of 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 :: LAMBDA-LIST & BODY CCL :: LABELS-FUNCTION-BODY).
[Условие типа CCL :: SIMPLE-PROGRAM- ОШИБКА]

Я не понимаю. Нужна помощь. Спасибо.


person Don Lun    schedule 08.05.2011    source источник
comment
Вы можете спутать скобки, изменяющие приоритет оператора, со списком, определяющим паретезис в lisp? т.е. (2 + 3) * 5 vs (a, b, c, d) ?? Это означает, что функция ожидает список списка в качестве второго параметра, но если вы удалите круглую скобку, это будет только список.   -  person xycf7    schedule 08.05.2011
comment
@ xycf7 - нет приоритета операторов, влияющих на паренсы в lisp, все операции на 100% однозначны, так как все операции должны быть полностью заключены в круглые скобки (2+3)*5 будет записано (* (+ 2 3) 5) в lisp   -  person tobyodavies    schedule 08.05.2011


Ответы (6)


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, и также не является самым верхним в трассировке. 4: (CCL::NX1-LABELS ... будет подсказкой (буфер отладчика на моем локальном компьютере).

Ознакомьтесь с документацией для labels в Hyperspec, чтобы узнать больше.

person danlei    schedule 08.05.2011

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

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

(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, называемых " Lisp-1 ", поэтому я считаю, что стоит упомянуть об этом здесь):

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

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

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

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

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

person ffriend    schedule 08.05.2011
comment
Вы правы в 99,9% случаев, но я думаю, что есть пара неясных случаев, когда круглые скобки на самом деле необязательны в CL. Например, (defstruct s f) и (defstruct s (f)). - person Ken; 08.05.2011
comment
@Ken: Ну, скобки вокруг f действительно кажутся необязательными, но на самом деле они определяют макрос с немного другим поведением: (defstruct s f) определяет только имя слота, а (defstruct s (f)) определяет имя слота, возможно, с параметрами initform и slot. И в каждом случае количество паролей строго определено. - person ffriend; 08.05.2011
comment
Я могу выбирать, помещать их туда или нет - это в значительной степени определение optional. Да, число строго определено как 0 или 1 набор парных знаков, что делает его необязательным. :-) Не уверен, что вы имеете в виду, говоря о возможностях initform и slot, поскольку я не уточняю их ни в том, ни в другом случае. - person Ken; 11.05.2011

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

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

person Nietzche-jou    schedule 08.05.2011

Круглые скобки важны и необходимы в Лиспе. Теперь вы можете понять, почему Land of В музыкальном видео Lisp говорится: "Я ем скобки на завтрак ... А если моя программа не завершена, я ем скобки на обед ... Они могут выглядеть забавно, но у них есть семантическая сила ... Это дает вашим программам много краткости и яркости. Скоро и вы будете мечтать о них!

person Terje Norderhaug    schedule 08.05.2011

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

(dolist (x L) (print x))

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

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

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

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

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

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

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

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

person 6502    schedule 08.05.2011

Как сказал @danlei, в первой части _1 _ / _ 2 _ / _ 3_ должен быть список определений функций. если это один элемент, то в итоге вы получите двойные круглые скобки, которые выглядят как дублирующие.

person tobyodavies    schedule 08.05.2011