Значение @(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:
Если за запятой сразу следует знак 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.