2010-03-23 14 views
15

Me gustaría poder definir lambdas usando la sintaxis Lisp común, en Clojure. Por ejemplo:¿Cómo implementar lambda como una función llamada "lambda" en Clojure?

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

Esto debe dar lugar a la misma como:

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

En mi caso, sé que siempre voy a tener exactamente un arg, así que quizás eso simplifica las cosas. (Pero se puede llamar cualquier cosa - "myarg" o lo que sea.)

Sospecho que una solución viable es "(defmacro lambda ...". Si es así, no estoy seguro de la mejor manera de proceder . ¿Cómo traducir el nombre limpiamente a arg%? Y cómo terminar con la función correcta?

O, ¿hay una solución simple que escribir mi propia macro que en realidad re-implementa de Clojure ... lambda?

Respuesta

25

#(foo %) es sólo una abreviatura de lector para (fn [arg] (foo arg)). No hay ninguna razón para escribir una macro que se expande en #(...). Todos los % en una construcción % se expanden en ge nsyms de inmediato de todos modos.

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

Si alguna vez escribir una macro que se expande para crear funciones anónimas, puede ser que también acaba de ampliar a fn forma a sí mismo. En su caso, probablemente debería simplemente usar fn directamente y omitir las macros. fn es Clojure's lambda.

La diferencia entre (fn [] ...) y (lambda() ...) en este caso es que "fn" es más corta de lo que escribir "lambda", y fn toma un vector para sus consolidaciones mientras que lambda toma una lista. Si está usando Clojure, tendrá que acostumbrarse a esto eventualmente, porque los vectores siempre se usan para colecciones de enlaces, en todos los formularios do y en for y binding etc. La razón detrás de esto, como yo lo entiendo, es que las listas se usan para llamadas a funciones o macro llamadas, y los vectores se usan para cosas que no son llamadas (listas de símbolos para vincular, por ejemplo). Podría decirse que hace que sea más fácil escanear el código visualmente que listas-todo-el-camino-abajo. Clojure no es Common Lisp, y experimentarás dolor si tratas de forzarlo.

Si realmente, realmente quería hacer esto, sólo para decir que hiciste:

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

Esto no permite que se pone una cadena de documentación o metadatos en su función, entre otras cosas. No creo que quieras utilizar esto en un programa Clojure real.

+2

Gracias Brian, esto es exactamente lo que necesitaba. Me avergüenza decir que tenía un punto ciego aquí ... Estoy tan enamorado del azúcar #() que olvidé que está el fn formal. Ahora, realmente realmente, realmente quiero usar el enfoque macro, porque estoy en una situación en la que me veo forzado a ejecutar un simple código Lisp que usa "lambda". Y la macro que escribiste es precisamente lo que necesitaba. ¡Muchas gracias! – dirtyvagabond

+0

Suena divertido, buena suerte. :) –

Cuestiones relacionadas