Лисп: список против S-выражения

Я сейчас изучаю Лисп. Я встретил 2 термина "список" и "S-выражение". Я просто не могу их различить. Являются ли они просто синонимами в Лиспе?


person Dagang    schedule 27.05.2012    source источник
comment
Для получения дополнительной информации см. вики C2 по секспрс.   -  person Asherah    schedule 27.05.2012


Ответы (5)


Во-первых, не все S-выражения представляют собой списки; такое выражение, как foobar, представляющее голый атом, также считается S-выражением. Как и синтаксис «cons-ячейки», (car . cons), используемый, когда часть «cons» сама по себе не является другим списком (или nil). Более знакомое выражение списка, такое как (a b c d), является просто синтаксическим сахаром для цепочки вложенных cons-ячеек; этот пример расширяется до (a . (b . (c . (d . nil)))).

Во-вторых, термин "S-выражение" относится к синтаксису - (items like this (possibly nested)). Такое S-выражение является представлением списка в исходном коде Lisp, но технически не является списком. Это различие такое же, как между последовательностью десятичных цифр и их числовым значением или между последовательностью символов в кавычках и результирующей строкой.

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

Например, рассмотрим это выражение:

(+ 1 2)

Выше приведено простое S-выражение, представляющее плоский список, состоящий из атомов +, 1 и 2.

Однако в программе на Лиспе такой список будет интерпретироваться как вызов функции + с 1 и 2 в качестве аргументов. (Обратите внимание, что интерпретируется именно список, а не S-выражение; оценщику передаются списки, которые были предварительно проанализированы читателем, а не исходный текст. кодовый текст.)

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

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

'(+ 1 2)
(quote (+ 1 2))
(list '+ 1 2)

Конечно, эквивалентность кода и данных — одна из замечательных особенностей Lisp, так что разница между ними незначительна. Но я хочу сказать, что, хотя все вышеперечисленное является S-выражениями и списками, только некоторые из них можно назвать «списками» в обычном языке Лиспа.

person Mark Reed    schedule 27.05.2012
comment
список представляет собой цепочку ячеек cons с NIL-дозорным. все это. читатель преобразует текст в S-выражения — в LISP все является S-выражением — это либо атом, либо cons-ячейка (векторы — это атомы и т. д.). читатель не пытается проверить аргумент для eval. - person Will Ness; 02.10.2016
comment
S-выражения не выводятся программой чтения. S-выражение относится к текстовому представлению со скобками и так далее. К тому времени, когда читатель закончит с этим, это уже не S-выражение, а уже фактический список в памяти - эта цепочка ячеек cons с нулевым дозорным, о которой вы упомянули. - person Mark Reed; 03.10.2016

S-выражения — это нотация для данных.

Исторически s-выражение (сокращение от символическое выражение) описывалось так:

  • символы, такие как FOO и BAR
  • cons-ячейки с s-выражениями в качестве первого и второго элемента: ( выражение-1 . выражение-2 )
  • символ завершения списка NIL
  • и соглашение о написании списков: ( A . ( B . NIL ) ) проще записать как список (A B)

Отметим также, что исторически текст программы писался по-разному. Пример для функции ASSOC.

assoc[x;y] =
   eq[caar[y];x] -> cadar[y];
   T -> assoc[x;cdr[y]]

Исторически существовало также отображение этих m-выражений (сокращение от метавыражений) в s-выражения. Сегодня большая часть программного кода на Лиспе написана с использованием s-выражений.

Это описано здесь: McCarthy, Recursive Functions of Symbolic Expressions

В современном языке программирования Lisp, таком как Common Lisp, s-выражения имеют больше синтаксиса и могут кодировать больше типов данных:

  • Символы: symbol123, |This is a symbol with spaces|
  • Числа: 123, 1.0, 1/3, ...
  • Струны: "This is a string"
  • Персонажи: #\a, #\space
  • Векторы: #(a b c)
  • Минусы и списки: ( a . b ), (a b c)
  • Комментарии: ; this is a comment, #| this is a comment |#

и больше.

Списки

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

Примечание: программы и формы

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

Например, вызов функции — это данные Лиспа, где вызов — это список с символом функции в качестве первого элемента, а следующие элементы — его аргументы.

Мы можем записать это как (sin 3.0). Но это действительно данные. Данные мы также можем построить.

Функция для оценки форм Лиспа называется EVAL, и она принимает данные Лиспа, а не текст программы или строки текста программы. Таким образом, вы можете создавать программы, используя функции Лиспа, которые возвращают данные Лиспа: (EVAL (LIST 'SIN 3.0)) оценивается как 0.14112.

Поскольку формы Лиспа имеют представление данных, они обычно пишутся с использованием внешнего представления данных Лиспа — а что? - с-выражения!

Это s-выражения. Лисп формируется, поскольку данные Лиспа записываются внешне как s-выражение.

person Rainer Joswig    schedule 27.05.2012
comment
Первыми появились S-выражения. Они никогда не предназначались для того, чтобы быть тем, что видел программист, а скорее промежуточным представлением. Однако потребовалось некоторое время, чтобы придумать представление верхнего уровня, М-выражения, и это не впечатлило команду. К тому времени все решили, что им нравятся S-выражения как есть. Так что даже исторически это всегда были S-выражения до самого низа; M-выражения в лучшем случае являются сноской. - person Mark Reed; 27.05.2012
comment
@Mark Reed: статья Маккарти 1960 года описывает как символические выражения, так и метавыражения. - person Rainer Joswig; 27.05.2012
comment
Так и есть, @rainerjoswig. Наверное, я неправильно запомнил. Спасибо за исправление. - person Mark Reed; 27.05.2012
comment
Вы сказали, что cons-ячейки с выражениями..., разве это не должны быть cons-ячейки с s-выражениями...? - person day; 13.06.2012
comment
Когда вы пишете, выражение-1 . выражение-2, возможно, вы действительно имели в виду .. s-выражение-1 . s-выражение-2 ? - person Elliptical view; 09.12.2018

Сначала вы должны понять основную особенность Лиспа - программой можно манипулировать как данными. В отличие от других языков (таких как C или Java), где вы пишете программу, используя специальный синтаксис ({, }, class, define и т. д.), в Лиспе вы пишете код в виде (вложенных) списков (кстати, это позволяет выразить непосредственно абстрактные синтаксические деревья). Еще раз: вы пишете программы, которые выглядят точно так же, как структуры данных языка.

Когда вы говорите об этом как о данных, вы называете это "списком", но когда вы говорите о программном коде, лучше использовать термин < strong>"s-выражение". Таким образом, технически они похожи, но используются в разных контекстах. Единственное реальное место, где эти термины смешиваются, — это метапрограммирование (обычно с макросами).

Также обратите внимание, что s-выражение также может состоять из одного атома (например, чисел, строк и т. д.).

person ffriend    schedule 27.05.2012
comment
s-выражение исторически является не программным кодом, а нотацией данных. Список — это структура данных. См. оригинальную статью Маккарти о Лиспе. - person Rainer Joswig; 27.05.2012
comment
@RainerJoswig: в качестве примера взгляните на mapcar определение из CLHS - в нем говорится, что mapcar работает с последовательными элементами списков. Списки, а не s-выражения. С другой стороны, редко можно увидеть, как интерпретатор фраз оценивает этот список..., в большинстве случаев вы увидите, как интерпретатор оценивает s-выражения... Вот как они используются теперь в популярная литература. Хотя (и я это подчеркивал) эти термины очень похожи и поэтому могли мешать на протяжении долгой истории Лиспа, особенно в научных статьях. - person ffriend; 27.05.2012
comment
@ffriend: конечно, mapcar работает со списками. Нет, eval не работает с s-выражениями. Он работает с формами Лиспа, представленными в виде данных. - person Rainer Joswig; 27.05.2012
comment
@RainerJoswig: данные сами по себе не могут представлять что-либо, по определению они являются значениями чего-то и сами должны быть каким-то образом представлены. В памяти данные о формах Лиспа могут быть представлены как вложенный список Лиспа, другой вид списка (не используемый в самом Лиспе), набор экземпляров класса Java, иерархия алгебраических типов данных в Haskell или что-то еще. В исходном коде (и из вопроса ясно, что OP был сбит с толку синтаксисом Лиспа) формы Лиспа представлены в виде текста, отформатированного как (имеющего обозначение) s-выражения. - person ffriend; 27.05.2012
comment
@ffriend: исходный код на Лиспе - это формы Лиспа. Некоторые из них имеют внешнее представление в виде текста, некоторые нет. Например замыкания, потоки, закрывающие объекты - они не имеют внешнего представления. Тем не менее, они могут быть частью форм Лиспа, как данные. - person Rainer Joswig; 27.05.2012
comment
@RainerJoswig: вы неправильно понимаете термин «исходный код». Помимо некоторых очень низкоуровневых и экзотических языков программирования, вы пишете программы, вводя символы в порядковые текстовые файлы. Введенный текст — это то, что мы называем исходным кодом. А в Лиспе этот текст имеет нотацию s-выражений. Этот текст позже преобразуется читателем в формы Лиспа. Но в текстовом файле это просто текст в какой-то нотации, как JSON или XML. - person ffriend; 27.05.2012
comment
@ffriend: Вот чем Lisp отличается. Исходный код — это данные. - person Rainer Joswig; 27.05.2012
comment
@RainerJoswig: взгляните на определение исходного кода в Википедии. В Лиспе программа представляется так же, как и данные, с которыми она работает в исходном коде. Но они могут иметь или не иметь одинаковое внутреннее представление - в памяти код Лиспа может быть скомпилирован и, таким образом, представлен как набор инструкций процессора, а данные представлены как связанные списки или другие структуры данных. Вы игнорируете разницу между исходным кодом (текстом), логической программой (то, что видит программист) и представлением в памяти и, таким образом, также игнорируете создаваемый ими контекст. - person ffriend; 28.05.2012
comment
@ffriend: Стандарт Common Lisp ANSI, глоссарий, запись для исходного кода: исходный код, сущ., код, представляющий объекты, подходящие для оценки (например, объекты, созданные чтением, расширением макроса или расширением макроса компилятора). Исходный файл: исходный файл, сущ., файл, содержащий текстовое представление исходного кода, который можно редактировать, загружать или компилировать. - person Rainer Joswig; 28.05.2012
comment
@RainerJoswig: это относится только к Common Lisp, но если вам не все равно, измените каждую запись исходного кода на исходный файл в моих комментариях, и вы должны понять идею. - person ffriend; 28.05.2012
comment
Вывод здесь, если оставить в стороне терминологические придирки, заключается в том, что функция Лиспа eval не работает со строками; в этом она отличается от одноименной функции в большинстве современных динамических языков. Вместо этого он ожидает, что его аргумент уже будет представлением кода в памяти, то есть (деревом иерархически вложенных) списков. читатель преобразует S-выражения в списки для оценки. Итак, S-выражения: текстовое представление списков. Сериализован, на самом деле, почти так же, как JSON или XML могут представлять дерево объектов. - person Mark Reed; 30.05.2012

Простое определение S-выражения:

(define S-expression?
    (λ (object)
        (or (atom? object) (list? object))))

;; Where atom? is:

(define atom?
  (λ (object) 
    (and (not (pair? object)) (not (null? object)))))

;; And list? is:

(define list? (λ (object)
  (let loop ((l1 object) (l2 object))
    (if (pair? l1)
        (let ((l1 (cdr l1)))
          (cond ((eq? l1 l2) #f)
                ((pair? l1) (loop (cdr l1) (cdr l2)))
                (else (null? l1))))
        (null? l1)))))
person dkinzer    schedule 15.03.2014

Оба написаны одинаково: (бла-бла-бла), могут быть вложенными. с одним отличием - списки начинаются с апострофа.

По оценке:

  • S-выражение возвращает некоторый результат (может быть атом, список, ноль или что-то еще)
  • Списки возвращают списки

Если нам нужно, мы можем преобразовать списки в s-exp и наоборот.

  • (eval '(бла-бла-бла)) => list обрабатывается как s-exp и возвращается результат.
  • (цитата (бла-бла-бла)) => sexp преобразуется в список, и список возвращается без оценки

МСФО:

  • Если список обрабатывается как данные, он называется списком, если он обрабатывается как код, он называется s-exp.
person Prabu    schedule 29.05.2012
comment
Если список обрабатывается как данные, он называется списком, если он обрабатывается как код, он называется s-exp. IME, если список обрабатывается как данные, он называется списком, в противном случае он называется как угодно - обычно это вызов функции. Термин s-expression зарезервирован специально для метатекстового описания синтаксиса. - person Mark Reed; 30.05.2012
comment
IME = по моему опыту - person Elliptical view; 09.12.2018