2011-10-17 11 views
5

Definiuję funkcję, która przyjmuje dwa parametry - mapę i klucz. Kluczem jest wymieniony z rozkładu parametru mapadefn vs. let z uwzględnieniem dekompozycji

(defn myfunc [{v k} k] 
    v) 

gdy zgłoszę:

(myfunc {:a 10} :a) 

Nieoczekiwanie produkuje oczekiwany wynik: 10

Podobnie rzecz na let:

(let [{v k} {:a 10} k :a] v) 

kończy się niepowodzeniem, ponieważ k nie jest zdefiniowany w moment, kiedy oceniana jest pierwsza część.

Moje pytanie brzmi: dlaczego dekompozycja wewnątrz parametrów funkcji zachowuje się inaczej w porównaniu do dekompozycji w wyrażeniach let?

Odpowiedz

3

Macroexpanding formularz defn ja dostać równowartość tej usuniętej .withMeta rzeczy (i sformatowane):

(def myfunc 
    (fn* myfunc 
     ([p__11393 k] 
      (let* [map__11394 p__11393 
       map__11394 (if (seq? map__11394) 
           (apply hash-map map__11394) 
           map__11394) 
       v   (get map__11394 k)] 
       v)))) 

Tak oto widzimy, że mapa {v k} jest w rzeczywistości pierwszy przypisany do zmiennej lokalnej p__11393. Następnie instrukcja if sprawdza, czy ta zmienna jest w rzeczywistości sekwencją i zamienia ją na tablicę haszującą, w przeciwnym razie pozostawia ją taką jaka jest. Co ważne, wartość przypisana do k jest wyświetlana na mapie po wszystko to dzieje się, więc działa to bezbłędnie (a także, gdyby :a nie było na mapie, get zwraca nil w tym przypadku).

Z drugiej strony macroexpanding formularz let uzyskać

(let* 
    [map__11431 
    {:a 10} 
    map__11431 
    (if (seq? map__11431) (apply hash-map map__11431) map__11431) 
    v 
    (get map__11431 k) 
    k 
    :a] 
    v) 

i tutaj widzimy, że v dostaje wynik (get map__11431 k), ale k nie jest zdefiniowana w tym momencie jeszcze, stąd ten błąd.

+0

Nasuwa się pytanie, czy taka różnica nie powinna być traktowana jako błąd lub jako element ... – aav

+0

Powiedziałbym jeśli wie się, że destrukturyzacja dzieje się wewnątrz ciała funkcji, nie jest to zaskakujące, a więc nie błąd. Ale myślę, że ten fakt powinien być lepiej wyjaśniony w odpowiednich miejscach - jeśli dobrze pamiętam, na przykład Joy of Clojure naprawdę się w to nie mieści. – Paul

+0

co jest interesujące (ale nie zaskakujące), że jego nie będzie działać: (defn myfunc [{v k} {k: k1}] v) – aav

0

To nie jest pełna odpowiedź, ale dodaje działa:

user=> (defn myfunc [{v k} k] v) 
#'user/myfunc 
user=> (myfunc {:a 10} :a) 
10 
user=> (let [k :a {v k} {:a 10}] v) 
10 
user=> 
+0

to oczywiście zadziała, ponieważ * k * jest zdefiniowany przed czymkolwiek innym – aav

Powiązane problemy