Вопрос о скобках в Lisp - PullRequest
7 голосов
/ 08 мая 2011

Этот фрагмент кода из книги: "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-ERROR]

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

Ответы [ 6 ]

10 голосов
/ 08 мая 2011

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 , чтобы узнать больше.

7 голосов
/ 08 мая 2011

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

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

(foo 1)

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

(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

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

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

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

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

3 голосов
/ 08 мая 2011

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

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

2 голосов
/ 08 мая 2011

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

1 голос
/ 08 мая 2011

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

(dolist (x L) (print x))

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

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

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

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

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

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

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

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

1 голос
/ 08 мая 2011

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

...