2011-09-03 19 views
7

Czy ktoś wie, jak wdrożyć metodę method_missing (à la Ruby) w Clojure? E.g.Metoda Clojure brakująca

(defn method_missing [name & args] 
    (foo name args)) 

Byłoby bardzo przydatne dla DSL, jeśli jest używany prawidłowo.

Z góry dziękuję!

+2

W jakich przypadkach chciałbyś wywołać tę funkcję? – Brian

Odpowiedz

10

W języku Ruby, method_missing jest jedną z głównych konstrukcji do metaprogramowania. Jest ściśle związana z obiektową strukturą Ruby, dynamicznie tworząc metody w klasie z "metaclasses". Można to zrobić, ponieważ w klasach Ruby są również obiekty.

Ponieważ Clojure jest językiem funkcjonalnym, naśladowanie tego rubinizmu ma niewielki sens. Jednak jednym z podstawowych idiomów Lisps (takich jak Clojure) jest to, że kod to dane: a ponieważ kod może generować dane, może również generować kod. Podstawowym sposobem wykonywania tego metaprogramowania w Lisp są makra.

Sugeruję więcej informacji na temat makr oraz ich zaleceń i zakazów. Należy jednak pamiętać, że tak jak w Ruby, generowanie dynamicznie kodu jest ogólnie trudniejsze do debugowania i utrzymywania. Często sprytne użycie innych funkcjonalnych idiomów może być lepszym rozwiązaniem konstrukcyjnym.

+3

Zgadzam się z większością tego, ale nie zgadzam się z twierdzeniem, że kod generowany dynamicznie jest trudny do debugowania lub utrzymywania. Makra są wielką korzyścią dla uproszczenia i łatwości konserwacji, pod warunkiem, że są wykorzystywane ze smakiem. – amalloy

+0

Chcąc wskazać, kiedy należy używać makr, należy dokładnie rozważyć, a kiedy można zrobić coś z normalnymi funkcjami, powinno to być preferowane. – NielsK

+1

Jako że sam pochodziłem z Ruby, zrozumienie mocy kompozycji funkcyjnej może zająć trochę czasu. Używanie makr do obejścia tego może przynieść efekt odwrotny do zamierzonego. – NielsK

5

Można utworzyć makro, które będzie zawijać wywołania funkcji w bloku try-catch, który przechwyciłby ten wyjątek.

np. Coś jak

(with-default-method [fxn args default] ...) 

rozwinie się do

(try (fxn args) (catch java.lang.IllegalArgumentException _) (finally default)) 

powyższe jest głównie ręcznie macha, bo nie sądzę, że jest to dobry pomysł w ogóle: to nadużycie systemu wyjątków, a Myślę, że zrobi nieoczekiwane rzeczy.

Nie jestem osobą z Rubinem, ale mam wrażenie, że ta funkcja jest wypalana w tym języku; w Javie, a przez rozszerzenie clojure, musielibyście spróbować to włączyć, a to nie byłoby ładne.