Jaka jest różnica między cytatem a listą?

Wiem, że możesz użyć ' (aka quote), Aby utworzyć listę, a ja używam tego cały czas, tak:

> (car '(1 2 3))
1
Ale nie zawsze działa tak, jak bym się spodziewał. Na przykład próbowałem utworzyć listę funkcji, jak ta, ale to nie zadziałało:
> (define math-fns '(+ - * /))
> (map (lambda (fn) (fn 1)) math-fns)
application: not a procedure;
  expected a procedure that can be applied to arguments
  given: '+

Kiedy używam list, działa:

> (define math-fns (list + - * /))
> (map (lambda (fn) (fn 1)) math-fns)
'(1 -1 1 1)
Dlaczego? Myślałem, że to tylko wygodny Skrót, więc dlaczego zachowanie jest inne?
Author: Will Ness, 2016-01-25

1 answers

TL;DR: są różne; używaj list gdy masz wątpliwości.

Zasada: używaj list gdy chcesz, aby argumenty zostały ocenione; quote "dystrybuuje" swoje argumenty, więc '(+ 1 2) jest jak (list '+ '1 '2). Skończysz z symbolem na liście, a nie funkcją.


Szczegółowe spojrzenie na list i quote

W Scheme i Racket, quote i list zupełnie innymi rzeczami , ale ponieważ oba mogą być użyte do tworzenia list, zamieszanie jest powszechne i zrozumiałe. Istnieje między nimi niezwykle ważna różnica: list jest zwykłą starą funkcją, podczas gdy quote (nawet bez specjalnej składni ') jest specjalną formą . Oznacza to, że {[22] } może być zaimplementowany w zwykłym schemacie, ale quote nie może być.

Funkcja list

Funkcja list jest zdecydowanie prostsza z tych dwóch, więc zacznijmy od tego. Jest to funkcja, która przyjmuje dowolną liczbę argumentów, a zbiera argumenty do listy.

> (list 1 2 3)
(1 2 3)

Powyższy przykład może być mylący, ponieważ wynik jest drukowany jako quoteable s-wyrażenie, i to prawda, w tym przypadku dwie składnie są równoważne. Ale jeśli będziemy nieco bardziej skomplikowani, zobaczysz, że jest inaczej: {]}

> (list 1 (+ 1 1) (+ 1 1 1))
(1 2 3)
> '(1 (+ 1 1) (+ 1 1 1))
(1 (+ 1 1) (+ 1 1 1))

Co się dzieje w przykładzie quote? Porozmawiamy o tym za chwilę, ale najpierw spójrz na list. To tylko zwykła funkcja, więc jest zgodna ze standardowym schematem oceny semantyka: ocenia każdy ze swoich argumentów zanim zostaną przekazane do funkcji. Oznacza to, że wyrażenia takie jak (+ 1 1) zostaną zredukowane do 2, zanim zostaną zebrane na liście.

To zachowanie jest również widoczne przy podawaniu zmiennych do funkcji list:

> (define x 42)
> (list x)
(42)
> '(x)
(x)

Z list, x jest oceniany przed przekazaniem do list. Z quote sprawy są bardziej skomplikowane.

Wreszcie, ponieważ list jest tylko Funkcją, to może być używany tak jak każda inna funkcja, w tym w sposób wyższego rzędu. Na przykład, może być przekazana do funkcji map i będzie działać odpowiednio:

> (map list '(1 2 3) '(4 5 6))
((1 4) (2 5) (3 6))

Formularz quote

Cytowanie, w przeciwieństwie do list, jest specjalną częścią Lispów. Forma quote jest po części wyjątkowa, ponieważ otrzymuje specjalny skrót czytnika, ', ale jest również specjalna, nawet bez tego. W przeciwieństwie do list, quote jest Nie funkcją, a zatem nie musi zachowywać się jak jeden-ma własne zasady.

Krótka dyskusja o kodzie źródłowym Lispu

W Lispie, którego Scheme i Racket są pochodnymi, cały kod składa się ze zwykłych struktur danych. Na przykład rozważmy następujące wyrażenie:

(+ 1 2)

To wyrażenie jest w rzeczywistości listą i ma trzy elementy:

  • symbol +
  • liczba 1
  • liczba 2

Wszystkie te wartości są wartościami normalnymi, które mogą być tworzone przez programistę. Bardzo łatwo jest utworzyć 1 wartość, ponieważ sama ocenia: wystarczy wpisać 1. Ale Symbole i listy są trudniejsze: domyślnie symbol w kodzie źródłowym przeszukuje zmienną! Oznacza to, że symbole nie są samooceną :

> 1
1
> a
a: undefined
  cannot reference undefined identifier

Jak się jednak okazuje, symbole są w zasadzie tylko ciągami znaków i w rzeczywistości możemy konwertować między oni:

> (string->symbol "a")
a

Listy robią więcej niż symbole, ponieważ domyślnie lista w kodzie źródłowym wywołuje funkcję! robi (+ 1 2) patrzy na pierwszy element listy, symbol +, wyszukuje powiązaną z nim funkcję i wywołuje ją wraz z resztą elementów na liście.

Czasami jednak możesz chcieć wyłączyć to" specjalne " zachowanie. Możesz po prostu pobrać listę lub uzyskać symbol bez jego oceny. Aby to zrobić, możesz użyj quote.

Znaczenie cytatu

Mając to wszystko na uwadze, jest dość oczywiste, co robi quote: po prostu "wyłącza" specjalne zachowanie oceny dla wyrażenia, które owija. Na przykład rozważmy quoteING symbol:

> (quote a)
a

Podobnie rozważmyquotelistę:

> (quote (a b c))
(a b c)

Bez względu na to, co dasz quote, zawsze będzie, zawsze wypluj to na siebie. Ani więcej, ani mniej. Oznacza to, że jeśli dasz mu listę, żadna z podwyrażeń nie będzie oceniana-nie oczekuj, że tak będzie! Jeśli potrzebujesz jakiejkolwiek oceny, użyj list.

Teraz Można zapytać: co się stanie, jeśli quote coś innego niż symbol lub lista? Odpowiedź brzmi:.. nic! Po prostu go Odzyskaj.

> (quote 1)
1
> (quote "abcd")
"abcd"

To ma sens, ponieważ quote nadal wypluwa dokładnie to, co mu dajesz. To dlatego "literały", takie jak Liczby i ciągi znaków, są czasami nazywane "autocytowaniem" w języku Lispu.

Jeden więcej: co się stanie, jeśli quote wyrażenie zawierające quote? To znaczy, co jeśli "podwoisz quote"?

> (quote (quote 3))
'3
Co tam się stało? Pamiętaj, że {[33] } jest w rzeczywistości bezpośrednim skrótem quote, więc nic specjalnego się nie wydarzyło! W rzeczywistości, jeśli twój schemat ma sposób na wyłączenie skrótów podczas drukowania, będzie wyglądał tak: {]}
> (quote (quote 3))
(quote 3)

Nie daj się zwieść quote bycie wyjątkowym: tak jak (quote (+ 1)), wynik jest po prostu zwykłą starą listą. W fakt, możemy dostać pierwszy element z listy: czy można zgadnąć, co to będzie?

> (car (quote (quote 3)))
quote

Jeśli zgadłeś 3, jesteś w błędzie. Pamiętaj, quote wyłącza wszystkie oceny , a wyrażenie zawierające symbol quote nadal jest zwykłą listą. Graj z tym w REPL, dopóki nie poczujesz się z tym komfortowo.

> (quote (quote (quote 3)))
''3
(quote (1 2 (quote 3)))
(1 2 '3)

Cytowanie jest niezwykle proste, ale może wydawać się bardzo złożone, ponieważ sprzeciwia się naszemu zrozumieniu tradycyjnego model oceny. W rzeczywistości jest to mylące , ponieważ z tego, jak proste jest to: nie ma specjalnych przypadków, nie ma zasad. Po prostu zwraca dokładnie to, co mu podajesz, dokładnie tak, jak podano (stąd nazwa "cytat").


Dodatek A: Quasiquotation

Więc jeśli cytowanie całkowicie wyłącza ocenę, do czego to jest dobre? Cóż, poza tworzeniem list ciągów, symboli lub liczb, które są znane z wyprzedzeniem, niewiele. Na szczęście koncepcja quasiquotation zapewnia sposób na wyrwanie się z cytatu i powrót do zwykłej oceny.

Podstawy są bardzo proste: zamiast używać quote, użyj quasiquote. W przeciwieństwie do tego, w jaki sposób jest on używany, nie można go używać.]}

> (quasiquote 3)
3
> (quasiquote x)
x
> (quasiquote ((a b) (c d)))
((a b) (c d))

To, co czyni quasiquote wyjątkowym, to rozpoznawanie specjalnego symbolu, unquote. Jeśli unquote pojawi się na liście, to jest zastępowane przez dowolne wyrażenie, które zawiera:

> (quasiquote (1 2 (+ 1 2)))
(1 2 (+ 1 2))
> (quasiquote (1 2 (unquote (+ 1 2))))
(1 2 3)

To pozwala używać quasiquote do twórz szablony, które mają "dziury" do wypełnienia unquote. Oznacza to, że możliwe jest uwzględnienie wartości zmiennych wewnątrz cytowanych list:

> (define x 42)
> (quasiquote (x is: (unquote x)))
(x is: 42)

Oczywiście, używanie quasiquote I unquote jest raczej słowne, więc mają własne skróty, tak jak '. W szczególności, quasiquote jest ` (backtick) i unquote jest , (przecinek). Z tymi skrótami powyższy przykład jest znacznie bardziej smakowity.

> `(x is: ,x)
(x is: 42)

Ostatni punkt: quasiquote w rzeczywistości można zaimplementować w Racket używając raczej owłosionego makra i tak jest. Rozszerza się do zastosowań list, cons, i oczywiście quote.


Dodatek B: wdrożenie list i quote W programie

Implementacja list jest bardzo prosta ze względu na to, jak działa składnia" rest argument". To wszystko czego potrzebujesz:

(define (list . args)
  args)

To jest to!

W przeciwieństwie, quote jest dużo trudniejsze-w rzeczywistości, to niemożliwe! Wydaje się to całkowicie wykonalne, ponieważ pomysł wyłączenia ewaluacji brzmi podobnie do makr. Jednak naiwna próba ujawnia kłopot:

(define fake-quote
  (syntax-rules ()
    ((_ arg) arg)))
Po prostu bierzemy i wyplujemy... ale to nie działa. Dlaczego nie? Cóż, wynik naszego makra zostanie oceniony, więc wszystko jest na nic. Możemy być w stanie rozszerzyć do czegoś w rodzaju quote, rozszerzając do (list ...) i rekurencyjnie cytując elementy, jak to:
(define impostor-quote
  (syntax-rules ()
    ((_ (a . b)) (cons (impostor-quote a) (impostor-quote b)))
    ((_ (e ...)) (list (impostor-quote e) ...))
    ((_ x)       x)))

Niestety, bez makr proceduralnych nie poradzimy sobie symbole bez quote. Możemy zbliżyć się do siebie używając syntax-case, ale nawet wtedy będziemy tylko emulować zachowanie quote, a nie replikować je.


Dodatek C: konwencje drukowania rakiet

Próbując przykładów w tej odpowiedzi w Racket, może się okazać, że nie drukują się tak, jak można by się spodziewać. Często mogą one drukować z wiodącym ', jak w tym przykładzie:

> (list 1 2 3)
'(1 2 3)

Dzieje się tak dlatego, że domyślnie wyświetla wyniki jako wyrażenia, gdy możliwe. Oznacza to, że powinieneś być w stanie wpisać wynik do REPL i odzyskać tę samą wartość. Osobiście uważam to zachowanie za miłe, ale może być mylące podczas próby zrozumienia cudzysłowu, więc jeśli chcesz go wyłączyć, zadzwoń (print-as-expression #f), lub zmień styl drukowania na "napisz" w menu języka DrRacket.

 51
Author: Alexis King,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-25 03:18:35