2010-03-23 9 views
15

Ich würde gerne in der Lage sein, lambdas mit der üblichen Lisp-Syntax in Clojure zu definieren. Zum Beispiel:Wie Lambda als eine Funktion namens "Lambda" in Clojure implementieren?

(lambda (myarg) 
    (some-functions-that-refer-to myarg)) 

Dies muss in dem gleichen wie führen:

#(some-functions-that-refer-to %) 

In meinem Fall, ich weiß, dass ich immer würde genau eine arg, so vielleicht, dass vereinfacht die Dinge. (Aber es kann alles genannt werden - "Myarg" oder was auch immer.)

Ich vermute, eine praktikable Lösung ist "(defcamro Lambda ...". Wenn ja, ich bin mir nicht sicher, der beste Weg, um fortzufahren . Wie sauber an den aRG Namen% übersetzen? Und wie mit der richtigen Funktion am Ende?

Oder gibt es eine einfachere Lösung als mein eigenes Makro zu schreiben, die tatsächlich Clojure ist erneut implementiert ... Lambda?

Antwort

25

#(foo %) ist nur Leserkurzschrift für (fn [arg] (foo arg)). Es gibt keinen Grund, ein Makro zu schreiben, das in #(...) expandiert.Alle % 's in einem #(...) Konstrukt sind in ge erweitert Nsyms sowieso sofort.

user> `#(foo % %1 %2) 
(fn* [user/p1__1877 user/p2__1878] 
    (user/foo user/p1__1877 user/p1__1877 user/p2__1878)) 

Wenn Sie jemals ein Makro zu schreiben, die anonyme Funktionen bauen erweitert, dann kann man auch nur um sie zu erweitern, um fn selbst bildet. In Ihrem Fall sollten Sie wahrscheinlich einfach fn verwenden und die Makros überspringen. fn ist Clojures lambda.

Der Unterschied zwischen (fn [] ...)(lambda() ...) und in diesem Fall ist, dass „fn“ einzugeben ist kürzer als „Lambda“ und fn nimmt einen Vektor für die Einbände während lambda eine Liste nimmt. Wenn Sie Clojure verwenden, müssen Sie sich irgendwann daran gewöhnen, da Vektoren immer für Sammlungen von Bindungen verwendet werden, in allen do Formularen und in for und binding usw. Das Grundprinzip dahinter ist, wie ich es verstehe, diese Listen werden für Funktionsaufrufe oder Makroaufrufe verwendet, und Vektoren werden für Dinge verwendet, die keine Aufrufe sind (zum Beispiel Listen von Symbolen zum Binden). Es macht es leichter, den Code visueller zu scannen als Listen - all-the-way-down. Clojure ist kein gewöhnliches Lisp und du wirst Schmerz empfinden, wenn du versuchst, es zu erzwingen.

Wenn Sie wirklich, wirklich wollte, dies zu tun, nur zu sagen, Sie haben:

user> (defmacro lambda [args & body] 
     `(fn ~(vec args) [email protected])) 
user> ((lambda (x) (println x)) "foo") 
foo 
nil 

Dieses dich nicht lassen eine docstring oder Metadaten auf Ihre Funktion setzen, unter anderem. Ich denke nicht, dass du das in einem echten Clojure-Programm verwenden möchtest.

+2

Danke Brian, das ist genau das, was ich brauchte. Es ist mir peinlich zu sagen, dass ich hier einen blinden Fleck hatte ... Ich bin so verliebt in den #() Zucker, dass ich vergessen habe, dass es das formale Fn gibt. Nun, ich möchte wirklich, wirklich, den Makro-Ansatz verwenden, weil ich in einer Situation bin, in der ich gezwungen bin, einfachen Lisp-Code auszuführen, der "Lambda" verwendet. Und das Makro, das Sie geschrieben haben, ist genau das, was ich brauchte. Vielen Dank! – dirtyvagabond

+0

Klingt nach Spaß, viel Glück. :) –