Kiedy piszesz:
(def foo "a")
(def bar "b")
(def zip "c")
pan zdefiniowano trzy symbole: foo
, bar
zip
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.
Nie ma żadnego skrótu do listy, ponieważ lista ma drugorzędne znaczenie dla Clojure. –