2015-01-28 5 views
5

Chcę, aby wygenerować nazwane funkcje z fn i zwrócić je z makra, próbowałem następujący przykład:Clojure fn nazwy wycieka poza jej zakresem gdy kompilowany na przodzie-of-time

(defmacro getfn 
    [namestr children] 
    `(fn fn-name# [] 
    (println "Recursing" ~namestr) 
    (doall (map (fn [child#] (child#)) ~children)))) 

(def foo (getfn "foo" [])) 
(def bar (getfn "bar" [foo])) 

(defn -main [& args] 
    (bar)) 

Wynikiem jest zazwyczaj zgodnie z oczekiwaniami:

Recursing bar 
Recursing foo 

jednak gdy uruchamiam ten opracowano na przodzie-of-time (AOT) uzyskać:

Recursing bar 
Recursing bar 
... 
Recursing bar 
Recursing bar 
Exception in thread "main" java.lang.StackOverflowError 

Uważam, że to dość dziwne, że pasek ciągle nazywa się sobą zamiast foo, jedynym sensownym powodem jest to, że wygenerowany symbol wycieka poza jego zasięg. Czy jest to błąd w Clojure lub w zamierzonym działaniu?

Aktualizacja: Dla jasności należy wspomnieć, że usunięcie fn-name# symbol i co funkcja anonimowa poprawki ten problem. Jednak w moim prawdziwym kodzie muszę czasem wywoływać go rekurencyjnie, więc nazwanie go jest konieczne.

Odpowiedz

1

Jedno rozwiązanie mam tego problemu jest użycie gensym aby otrzymać nowy symbol dla każdej wersji makro, to będzie działać poprzez modyfikację getfn następująco:

(defmacro getfn 
    [namestr children] 
    `(let [fn-name# (gensym)] 
    (fn fn-name# [] 
     (println "Recursing" ~namestr) 
     (doall (map (fn [child#] (child#)) ~children))))) 

to czuje się trochę zbędne, ponieważ z definicji nazwa fn powinna być istotna tylko w jej własnym zakresie.

Aktualizacja: tylko przetestowane z wydań alfa i wydaje Clojure 1.7.0-wobec alfa3 i późniejsze prace bez tego siekać, Clojure 1.7.0-alfa 2 i wcześniej są podzielone. Korzystanie z tego obejścia jest prawdopodobnie w porządku, dopóki nie zostanie wydana stabilna wersja wersji 1.7.0, chyba że ktoś może wymyślić coś lepszego.

+1

Problem związany z rozwiązaniem problemu: http://dev.clojure.org/jira/browse/CLJ-1330 –

Powiązane problemy