2012-04-24 14 views
18

Sekcja na listach wydaje się wskazywać, że '() jest konstruktorem listy, podobnie jak (list), ale odkryłem, że w praktyce nie są one dokładnie takie same. Na przykład, biorąc pod uwagę:Jaka jest różnica między "() i (list) w Clojure?

(def foo "a") 
(def bar "b") 
(def zip "c") 

następujące oświadczenie:

(apply str '(foo bar zip)) 

produkuje wyjściowy "foobarzip", która nie spodziewałbym.

Ale podobno równoważne:

(apply str (list foo bar zip)) 

produkuje "abc", jak ja się spodziewać.

Co tu się dzieje? Jeśli istnieje "stenografia" dla listy w Clojure (jak {} dla map i [] dla wektorów), co to jest?

+0

Nie ma żadnego skrótu do listy, ponieważ lista ma drugorzędne znaczenie dla Clojure. –

Odpowiedz

31

W sepsach ' (np. quote) przytacza swoje argumenty, tj. Zachowuje je dokładnie tak, jak napisane w ich formularzu s-exp, w tym nie oceniając niczego w obrębie.

Innymi słowy '(foo bar zip) tworzy listę zawierającą symbole: foo, bar, zip; podczas gdy (list foo bar zip) tworzy listę zawierającą wartości z foo, bar, zip. W pierwszym przypadku, str będzie konwertować same symbole na ciągi, a następnie je łączyć.

Jako demonstrację to:

=> (def foo "a") 
=> (type (first '(foo))) 
clojure.lang.Symbol 
=> (type (first (list foo))) 
java.lang.String 
+2

@ Jonathan Z mojego doświadczenia wynika, że ​​zazwyczaj wygodniej jest używać wektora zamiast cytowanej listy. Oprócz mniejszej liczby naciśnięć klawiszy wektor łatwiej odróżnić jako listę nieuwarunkowaną niż listę cytowaną. – user100464

+0

Czy możesz również skomentować puste przypadki: ''()' i '(lista)'? Czy jest między nimi jakaś różnica? – Lii

+0

@Lii nie, uważam, że są takie same. – huon

10

Różnica polega na tym, że, jak widać, dosłowne składnia '() jest cytowany. Oznacza to, że symbole wewnątrz nie są oceniane. Aby korzystać z list literałów przy ocenie elementy można wykorzystać makra syntax-quote czytelnika:

user=> (apply str `(~foo ~bar ~zip)) 
"abc" 
3

Kiedy piszesz:

(def foo "a") 
(def bar "b") 
(def zip "c") 

pan zdefiniowano trzy symbole: foo, barzip i związane z wartościami: "a", "b" i "c".

Stowarzyszenie jest przechowywany wewnątrz tabeli namsepace, więc jeśli używasz rEPL, przestrzeń nazw byłoby user domyślnie, więc tabela nazw użytkownik będzie teraz zawierać:

{foo 
#'user/foo 
bar 
#'user/bar, 
zip 
#'user/zip} 

można zobaczyć tabelę namespace przez robienie: (ns-interns *ns*)

Teraz, jeśli napiszesz: (foo bar zip) wewnątrz Clojure, będą cztery różne sposoby, które może odczytać czytelnik. Musisz określić czytelnikowi, w jaki sposób należy ją przeczytać. W tym momencie wchodzą w grę `, ' i list.

przypadku nie wskaźnika:

(foo bar zip) 

Po prostu napisany bez wskaźnika, czytnik interpretuje to jako S ekspresji i interpretuje foo w odwzorowywaniu symbolu do funkcji z bar i zip jako odwzorowywanie symboli na wartości przekazywane do funkcji foo.

W naszym przypadku, to rzut wyjątek:

java.lang.ClassCastException: java.lang.String cannot be cast to clojure.lang.IFn 

Dzieje się tak dlatego żadna funkcja foo zostało zdefiniowane foo wiązało z "a", który jest ciągiem znaków, nie IFN (funkcja Clojure).

Jeśli funkcja foo została zdefiniowana, to nazwali foo przekazując jako argument "b" i "c".

przypadek list:

(list foo bar zip) 

przypadku korzystania z listy symbol, czytelnik jest właściwie interpretując ten sam sposób jak w przypadku brak wskaźnika. Oznacza to, że szuka symbolu list, który odwzorowuje funkcję, która jako argumenty przyjmie skojarzone wartości odwzorowane na foo, bar i zip. Funkcja list jest wstępnie zdefiniowana przez Clojure wewnątrz przestrzeni nazw clojure.core; zwraca listę jego argumentów.

Kiedy więc czytelnik szuka list, odnajduje funkcję clojure.core, następnie szuka symbolu foo i stwierdza, że ​​mapuje on na "a" i tak dalej. Po znalezieniu wszystkich mapowań dla symboli, wywołuje list i przekazuje mu powiązane wartości foo bar zip, które byłyby "a" "b" "c". Tak więc (list foo bar zip) jest taki sam jak (list "a" "b" "c").

przypadek ':

'(foo bar zip) 

' cytat mówi czytelnikowi, że postać, która ma być następujący czytać jak jest. W naszym przypadku foo, bar i zip są symbolami, a (foo bar zip) jest listą symboli. Czytelnik zinterpretuje to jako listę symboli.

Dlatego po uruchomieniu (apply str '(foo bar zip)) zadzwoni ona pod numer str 'foo 'bar 'zip, który poda foobarzip. Oznacza to, że zamieni każdy symbol na liście symboli na reprezentację String, a następnie połączyć je w jeden String.

Przyjmując formularz w niezmienionym stanie, przekazuje jako argument listę symboli, bez oceny symboli, tj. Bez szukania, z czym są one powiązane. Jeśli uruchomiłeś (eval '(foo bar zip)), przeszedłbyś listę symboli do eval, a eval oceniłaby symbole na wartości i zwróciła listę wartości, do których symbole są zamapowane. Więc możesz pomyśleć o cytacie ' jako o przekazaniu kodu jako kodu.

przypadek `:

`(foo bar zip) 

Ten jest trochę bardziej skomplikowana. Czytnik zobaczy wsteczną odpowiedź ` i rozrysuje symbole wewnątrz listy symboli rekurencyjnie, aby uzyskać listę w pełni kwalifikowanych symboli.

Zasadniczo, gdy czytelnik wyszukuje symbole w tabeli symboli, robi to z tabeli symboli aktualnej przestrzeni nazw. W pełni kwalifikowany symbol to symbol zawierający informacje o przestrzeni nazw. Dlatego po uruchomieniu `(foo bar zip) czytnik zastąpi te symbole w pełni kwalifikowanymi, przekształcając je w (user.foo user.bar user.zip).

Można powiedzieć czytelnikowi, aby ocenił niektóre elementy na liście, zmieniając inne na w pełni kwalifikowane symbole. Aby to zrobić, trzeba poprzedzić symboli, które mają być oceniane z ~ jak w:

`(foo ~bar zip) 

daje

(clojure.foo "b" clojure.zip) 

wydajnie backquote ` jest dużo podobnych do cytatu ' tym, że robi nie ocenia, ale po prostu zwraca kod, z wyjątkiem tego, że manipuluje kodem, który ma zostać zwrócony, poprzez pełne kwalifikowanie symboli w nim. Ma to wpływ na makra, gdzie czasami możesz potrzebować w pełni kwalifikowanego odnośnika, aby pobrać z innego obszaru nazw, a czasami chcesz elastyczności w mówieniu, poszukaj tego symbolu w bieżącym obszarze nazw.

Powiązane problemy