Значение @(at-sign) в Lisp?

Вы все знаете историю: программист читает код других людей, программист видит символ, который они не понимают, Google терпит неудачу, потому что трудно искать не-буквенно-цифровые символы.

На этот раз это символ @, который, кажется, используется для ввода содержимого одного списка в середину другого. Например:

`(5 6 7 ,@'(8 9) 10 11)
;=> (5 6 7 8 9 10 11)

Мне это нравится, но мне интересно, правильно ли я понимаю поведение @? Есть ли у него другие виды использования? И что вызывает ошибку в следующем расшифровке (из CLISP)?

[1]> (list 1 2 3 4 @'(5 6 7))

*** - SYSTEM::READ-EVAL-PRINT: variable @ has no value

Наконец, что такое @? Это не похоже на функцию:

[3]> (print #'@)

*** - FUNCTION: undefined function @

Я предполагаю, что это фундаментальный синтаксис, такой как backquote (`) или запятая (,). Это верно? Извините, если это дубликат, но еще раз, насколько я знаю, невозможно найти @.

Ответы

Ответ 1

", @" используется для сращивания внутри backquotes...

Он описан в HyperSpec в разделе в backquote:

2.4.6 Backquote

Если за запятой сразу следует знак at, то форма после оценки at-sign вычисляется для создания списка объектов. Эти объекты затем "сращиваются" на месте в шаблоне. Например, если x имеет значение (a b c), то

 `(x ,x ,@x foo ,(cadr x) bar ,(cdr x) baz ,@(cdr x))
=>  (x (a b c) a b c foo b bar (b c) baz b c)

Стоит отметить, что ,@ не всегда необходимо; в соответствии с той же документацией:

В любом месте ", @" может использоваться синтаксис ",". может использоваться вместо указывают, что разрешено действовать деструктивно в списке структура, созданная по форме, следующей за ",". (по сути, использовать nconc вместо append).

... но "@" сам по себе является еще одной буквой...

Ваша интуиция в основном правильна, когда вы спрашиваете, "поэтому в принципе @сам по себе ничего не значит, и единственным реальным оператором является @?" @ может использоваться в других местах как обычная буква. Вот почему вы получили сообщение об ошибке: (list 1 2 3 4 @'(5 6 7)) просто

(list 1 2 3 4 @ '(5 6 7))

и @ - переменная, но здесь она не имеет значения. Сравните это с:

(let ((@ 4.5))
  (list 1 2 3 4 @ '(5 6 7)))
;=> (1 2 3 4 4.5 (5 6 7))

... что, к сожалению, трудно найти.

Извините, если это дубликат, но еще раз, насколько я знаю, это невозможно найти "@".

Поиск документации по некоторым не-буквенно-цифровым символам может быть затруднен, но я нашел несколько методов, которые могут помочь. Например, если вы перейдете на страницу lispdoc.com, вы можете выполнить поиск comma, а результаты там помогут вам отправиться в backquote. (Поиск по-знаку не помог, хотя.) Это не идеальное решение, но иногда это может помочь.

Ответ 2

,@ следует рассматривать как единый объект, а значение ,@ заключается в том, что следующие выражения сплайсируются в текущий список с квазициклированием.

Например, вы не можете использовать

`,@x

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

`(list ,@5)

потому что 5 не является списком (однако оба SBCL и CLISP разрешают его и расширяют до (list . 5)).

ИЗМЕНИТЬ

Собственно, поведение SBCL и CLISP приемлемо, но также приемлемо, чтобы совместимая реализация выдавала ошибку, если ,@ используется с аргументом non-list.

CLHS раздел 2.4.6 последнее возможное расширение для `((,a b) ,c ,@d) показывает, что повышение ошибки для не-списка также может быть приемлемым.

Ответ 3

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