Symbol, który znajduje się w pozycji niefunkcjonalnej, jest traktowany jako nazwa zmiennej. In (function variable)
function
znajduje się w pozycji funkcji (po nawiasie otwierającym) i variable
nie jest. Chyba, że zmienne podane wprost są zastępowane ich wartościami.
Jeśli miałbyś pisać (boundp my-variable)
, oznaczałoby to „to symbol, który jest przechowywany w wartości zmiennej my-variable
związanej jako zmienna”, a nie „to symbol my-variable
związany jako zmienna.
Dlaczego więc bound-and-truep
zachowuje się inaczej?
Jest to makro i nie mają tu zastosowania normalne reguły oceny (funkcji), makra mogą swobodnie decydować, czy i kiedy ich argumenty zostaną ocenione. Makra faktycznie przekształcają argumenty i zwracają wynik jako listę, która jest następnie analizowana. Transformacja i ocena końcowa odbywają się w różnych momentach, zwanych czasem ekspansji makr i czasem oceny.
Oto bound-and-true-p
jak wygląda definicja :
(defmacro bound-and-true-p (var)
"Return the value of symbol VAR if it is bound, else nil."
`(and (boundp (quote ,var)) ,var))
Używa to makr czytnika, które różnią się od makr lisp (więcej na ten temat poniżej). Aby to nie komplikować, nie używajmy żadnych makr czytników:
(defmacro bound-and-true-p (var)
"Return the value of symbol VAR if it is bound, else nil."
(list 'and (list 'boundp (list 'quote var)) var))
Jeśli napiszesz
(bound-and-true-p my-variable)
to jest najpierw „przetłumaczone” na
(and (boundp 'my-variable) my-variable)
a następnie jest to zwracane, nil
jeśli my-variable
nie jest, boundp
lub wartość my-variable
(która oczywiście może być nil
).
Być może zauważyłeś, że rozszerzenie nie było
(and (boundp (quote my-variable)) my-variable)
jak mogliśmy się spodziewać. quote
to specjalna forma, a nie makro lub funkcja. Podobnie jak makra, specjalne formularze mogą zrobić wszystko z ich argumentami. Ta szczególna specjalna forma po prostu zwraca swój argument, tutaj symbol, zamiast zmiennej wartości symbolu. To właściwie jedyny cel tej specjalnej formy: zapobieganie ewaluacji! Makra nie można zrobić na własną rękę, trzeba użyć quote
, aby to zrobić.
Więc o co chodzi '
? Jest to makro czytnika , które, jak wspomniano powyżej, nie jest tym samym, co makro lisp . Podczas gdy makra są używane do przekształcania kodu / danych, makra czytające są używane wcześniej podczas czytania tekstu w celu przekształcenia tego tekstu w kod / dane.
'something
jest krótką formą dla
(quote something)
`
w rzeczywistej definicji bound-and-true-p
również używane jest makro czytnika. Jeśli cytuje on symbol taki jak w `symbol
nim, jest on równoważny 'symbol
, ale kiedy jest używany do cytowania listy, ponieważ `(foo bar ,baz)
zachowuje się inaczej w tym, że ,
oceniane są formularze z prefiksem .
`(constant ,variable)
jest równa
(list (quote constant) variable))
Powinno to odpowiedzieć na pytanie, dlaczego niecytowane symbole są czasami oceniane (zastępowane ich wartościami), a czasem nie; makra mogą służyć quote
do zapobiegania ocenie symboli.
Ale dlaczego bound-and-true-p
makro boundp
nie jest? Musimy być w stanie ustalić, czy dowolne symbole, które nie są znane do czasu wykonania, są powiązane jako symbole. Nie byłoby to możliwe, gdyby boundp
argument był cytowany automatycznie.
bound-and-true-p
służy do ustalenia, czy znana zmienna jest zdefiniowana, a jeśli tak, użyj jej wartości. Jest to przydatne, jeśli biblioteka ma opcjonalną zależność od biblioteki innej firmy, jak w:
(defun foo-get-value ()
(or (bound-and-true-p bar-value)
;; we have to calculate the value ourselves
(our own inefficient or otherwise undesirable variant)))
bound-and-true-p
można zdefiniować jako funkcję i wymagać cytowania argumentu, ale ponieważ jest on przeznaczony do przypadków, w których wiadomo z góry, jaką zmienną, na której Ci zależy, makro użyto, aby uniknąć konieczności wpisywania '
.
setq
oznaczaset quoted
, i pierwotnie było makrem, które się rozszerzyło(set 'some-variable "less")
. Ogólnie rzecz biorąc, Elisp nie jest strasznie konsekwentny w argumentach cytowanych i niecytowanych, ale każda funkcja (nie makro), która musi wchodzić w interakcje ze zmienną zamiast wartości, przyjmuje cytowany argument (setq
jest to główny wyjątek).