Lisp: списък срещу S-израз

Сега уча Lisp. Срещнах 2 термина "списък" и "S-израз". Просто не мога да ги различа. Дали са само синоними в Lisp?


person Dagang    schedule 27.05.2012    source източник
comment
За повече информация вижте C2 wiki за sexprs.   -  person Asherah    schedule 27.05.2012


Отговори (5)


Първо, не всички S-изрази представляват списъци; израз като foobar, представляващ гол атом, също се счита за S-израз. Както и синтаксисът "против клетка", (car . cons), използван, когато частта "против" сама по себе си не е друг списък (или нула). По-познатият списъчен израз, като (a b c d), е просто синтактична захар за верига от вложени cons клетки; този пример се разширява до (a . (b . (c . (d . nil)))).

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

Това може би е прекалено техническо разграничение; програмистите рутинно се позовават на буквални представяния на стойности, сякаш те са самите стойности. Но с Lisp и списъците нещата стават малко по-трудни, защото всичко в програмата на Lisp технически е списък.

Например, разгледайте този израз:

(+ 1 2)

Горното е ясен S-израз, който представлява плосък списък, състоящ се от атомите +, 1 и 2.

Въпреки това, в рамките на програма на Lisp, такъв списък ще се интерпретира като извикване на функцията + с 1 и 2 като аргументи. (Имайте предвид, че така се интерпретира списъкът, а не S-изразът; на оценителя се дават списъци, които са били предварително анализирани от читателя, а не от източника кодов текст.)

Така че докато горният S-израз представлява списък, той рядко би бил наричан като "списък" в контекста на програма на Lisp. Освен ако не обсъжда макроси или вътрешната работа на читателя, или не е ангажиран в метасинтактична дискусия поради някакъв друг контекст на генериране на код или анализиране, типичният програмист на Lisp вместо това би третирал горното като числов израз.

От друга страна, който и да е от следните S-изрази вероятно ще бъде наричан "списъци", защото оценяването им като Lisp код ще произведе списъка, представен от горния литерал S-израз като време за изпълнение стойност:

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

Разбира се, еквивалентността на код и данни е едно от готините неща за Lisp, така че разграничението е течно. Но моята гледна точка е, че докато всички по-горе са S-изрази и списъци, само някои биха били посочени като "списъци" в случайния Lisp-говор.

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

S-изразите са нотация за данни.

Исторически s-израз (съкратено от символичен израз) се описва като:

  • символи като FOO и BAR
  • против клетки със 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-изрази. Днес повечето програмен код на Lisp е написан с помощта на 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 |#

и още.

Списъци

Списъкът е структура от данни. Състои се от клетки с минуси и маркер за край на списъка. Списъците имат в Lisp нотация като списъци в s-изрази. Можете да използвате някои други обозначения за списъци, но в Lisp човек се е спрял на синтаксиса на s-израз, за ​​да ги напише.

Странична бележка: програми и формуляри

В език за програмиране като Common Lisp, изразите на езика за програмиране не са текст, а данни! Това е различно от много други езици за програмиране. Изразите в езика за програмиране Common Lisp се наричат ​​Lisp forms.

Например извикването на функция е Lisp данни, където извикването е списък с функционален символ като негов първи елемент, а следващите елементи са неговите аргументи.

Можем да запишем това като (sin 3.0). Но това наистина са данни. Данни, които също можем да конструираме.

Функцията за оценяване на Lisp форми се нарича EVAL и взема Lisp данни, а не програмен текст или низове от програмен текст. По този начин можете да създавате програми, използвайки Lisp функции, които връщат Lisp данни: (EVAL (LIST 'SIN 3.0)) оценява на 0.14112.

Тъй като формите на Lisp имат представяне на данни, те обикновено се пишат с помощта на външно представяне на данни на Lisp - което е какво? - s-изрази!

Това са s-изрази. Формите на Lisp като данни на Lisp се записват външно като s-израз.

person Rainer Joswig    schedule 27.05.2012
comment
S-изразите са на първо място. Те никога не са били предназначени да бъдат това, което програмистът вижда, а по-скоро междинно представяне. Въпреки това отне известно време, за да се измисли представянето на най-високо ниво, M-изразите, и това не впечатли екипа. По това време всички бяха решили, че харесват S-изразите такива, каквито са. Така че дори исторически, винаги е имало S-изрази докрай; М-изразите са в най-добрия случай бележка под линия. - person Mark Reed; 27.05.2012
comment
@Марк Рийд: Статията на Маккарти от 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

Първо трябва да разберете основната функция на Lisp - програмата може да се манипулира като данни. За разлика от други езици (като C или Java), където пишете програма, като използвате специален синтаксис ({, }, class, define и т.н.), в Lisp пишете код като (вложени) списъци (между другото, това позволява да изразите абстрактни синтактични дървета директно). Още веднъж: пишете програми, които изглеждат точно като структурите от данни на езика.

Когато говорите за това като данни, вие го наричате "списък", но когато говорите за програмен код, трябва по-добре да използвате термина < strong>"s-израз". Следователно технически те са сходни, но се използват в различен контекст. Единственото реално място, където тези термини се смесват, е мета-програмирането (обикновено с макроси).

Също така имайте предвид, че s-изразът може също да се състои от единствения атом (като числа, низове и т.н.).

person ffriend    schedule 27.05.2012
comment
s-израз исторически не е програмен код, а нотация на данни. Списъкът е структура от данни. Вижте оригиналната статия на McCarthy за Lisp. - person Rainer Joswig; 27.05.2012
comment
@RainerJoswig: като пример разгледайте mapcar дефиниция от CLHS - тя казва, че mapcar работи върху последователни елементи от списъците. Списъци, не s-изрази. От друга страна, рядко можете да видите интерпретатор на фрази да оценява този списък..., в повечето случаи ще видите интерпретатор да оценява s-изрази... Ето как те се използват сега в популярна литература. Въпреки че (и аз подчертах това) тези термини са много сходни и по този начин могат да се намесят по време на дългата история на Lisp, особено в научни статии. - person ffriend; 27.05.2012
comment
@ffriend: разбира се, mapcar работи със списъци. Не, eval не работи върху s-изрази. Работи върху форми на Lisp, представени като данни. - person Rainer Joswig; 27.05.2012
comment
@RainerJoswig: данните сами по себе си не могат да представляват нищо, по дефиниция те са стойности на нещо и самите те трябва да бъдат представени по някакъв начин. В паметта данните за формите на Lisp могат да бъдат представени като вложен списък на Lisp, друг вид списък (не се използва в самия Lisp), набор от екземпляри на Java клас, йерархия на алгебрични типове данни в Haskell или нещо друго. В изходния код (и от въпроса става ясно, че OP е бил объркан относно синтаксиса на Lisp) формите на Lisp са представени като текст, форматирани като (с нотация на) s-изрази. - person ffriend; 27.05.2012
comment
@ffriend: изходният код в Lisp са Lisp форми. Някои от тях имат външно представяне като текст, други не. Например затваряния, потоци, затворени обекти - те нямат външно представяне. Все пак те могат да бъдат част от формулярите на Lisp, като данни. - person Rainer Joswig; 27.05.2012
comment
@RainerJoswig: разбирате погрешно термина изходен код. Освен някои много ниско ниво и екзотични езици за програмиране, вие пишете програми, като въвеждате знаци в обикновени текстови файлове. Въведеният текст е това, което наричаме изходен код. И в Lisp този текст има нотация на s-изрази. Този текст по-късно се трансформира във форми на Lisp от читателя. Но в текстов файл това е просто текст в някаква нотация, точно като JSON или XML. - person ffriend; 27.05.2012
comment
@ffriend: Това е мястото, където Lisp е различен. Изходният код е данни. - person Rainer Joswig; 27.05.2012
comment
@RainerJoswig: погледнете дефиницията на изходния код в Wikipedia. В Lisp програмата е представена по същия начин като данните, с които работи в изходния код. Но те могат или не могат да имат едно и също представяне вътрешно - в паметта кодът на Lisp може да бъде компилиран и по този начин да бъде представен като набор от инструкции на процесора, докато данните са представени като свързани списъци или други структури от данни. Вие пренебрегвате разликата между изходния код (текст), логическата програма (това, което програмистът вижда) и представянето в паметта и по този начин игнорирате контекста, който създават. - person ffriend; 28.05.2012
comment
@ffriend: Common Lisp ANSI Standard, Речник, запис за изходен код: изходен код, n., код, представляващ обекти, подходящи за оценка (напр. обекти, създадени чрез четене, чрез разширяване на макроси или чрез разширяване на макроси на компилатор). Изходен файл: изходен файл, n., файл, който съдържа текстово представяне на изходния код, който може да бъде редактиран, зареден или компилиран. - person Rainer Joswig; 28.05.2012
comment
@RainerJoswig: това е специфично само за Common Lisp, но ако ви интересува, променете всеки запис на изходния код в изходния файл в моите коментари и трябва да схванете идеята. - person ffriend; 28.05.2012
comment
Изводът тук, като оставим настрана терминологичните гниди, е, че функцията Lisp 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 '(blah blah blah)) => списъкът се третира като s-exp и се връща резултат.
  • (quote (blah blah blah)) => sexp се преобразува в списък и списъкът се връща без оценка

IAS:

  • Ако списъкът се третира като данни, той се нарича Списък, ако се третира като код, се нарича 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