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? 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
są 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 quote
able 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 quote
ING symbol:
> (quote a)
a
Podobnie rozważmyquote
listę:
> (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.
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