Taquigrafía de función anónima

85

Hay algo que no entiendo sobre las funciones anónimas que usan la notación corta # (..)

Los siguientes trabajos:

REPL>  ((fn [s] s) "Eh")
"Eh"

Pero esto no:

REPL>  (#(%) "Eh")

Esto funciona:

REPL> (#(str %) "Eh")
"Eh"

Lo que no entiendo es por qué (# (%) "Eh") no funciona y, al mismo tiempo, no necesito usar str en ((fn [s] s) "Eh")

Ambas son funciones anónimas y ambas toman, aquí, un parámetro. ¿Por qué la notación abreviada necesita una función mientras que la otra notación no?

Cedric Martin
fuente

Respuestas:

126
#(...)

es la abreviatura de

(fn [arg1 arg2 ...] (...))

(donde el número de argN depende de la cantidad de% N que tenga en el cuerpo). Entonces cuando escribes:

#(%)

se traduce a:

(fn [arg1] (arg1))

Tenga en cuenta que esto es diferente de su primera función anónima, que es como:

(fn [arg1] arg1)

Su versión devuelve arg1 como valor, la versión que proviene de expandir la abreviatura intenta llamarlo como una función. Obtiene un error porque una cadena no es una función válida.

Dado que la abreviatura proporciona un conjunto de paréntesis alrededor del cuerpo, solo se puede usar para ejecutar una única llamada de función o un formulario especial.

Barmar
fuente
64

Como las otras respuestas ya han señalado muy bien, lo #(%)que publicó en realidad se expande a algo como (fn [arg1] (arg1)), que no es en absoluto lo mismo que (fn [arg1] arg1).

@John Flatness señaló que solo puede usar identity, pero si está buscando una forma de escribir identityusando la #(...)macro de envío, puede hacerlo así:

#(-> %)

Al combinar la #(...)macro de despacho con la ->macro de subprocesos , se expande a algo como (fn [arg1] (-> arg1)), que se expande nuevamente a (fn [arg1] arg1), que es lo que deseaba. También encuentro útil el combo ->y #(...)macro para escribir funciones simples que devuelven vectores, por ejemplo:

#(-> [%2 %1])
DaoWen
fuente
20

Cuando lo usa #(...), puede imaginar que en su lugar está escribiendo (fn [args] (...)), incluidos los paréntesis que comenzó justo después de la libra.

Entonces, su ejemplo que no funciona se convierte en:

((fn [s] (s)) "Eh")

que obviamente no funciona porque estás intentando llamar a la cadena "Eh". Tu ejemplo con strfunciona porque ahora tu función es en (str s)lugar de (s). (identity s)sería el análogo más cercano a su primer ejemplo, ya que no obligará a str.

Tiene sentido si lo piensas, ya que aparte de este ejemplo totalmente mínimo, cada función anónima llamará a algo , por lo que sería un poco tonto requerir otro conjunto anidado de parens para realizar una llamada.

John Flatness
fuente