2010-04-05 15 views
5

Si hago lo siguiente:(str aplicar parcial) y aplicar en-str de clojure ->

user=> (-> ["1" "2"] (partial apply str)) 
#<core$partial__5034$fn__5040 [email protected]> 

... me sale una función parcial posterior. Sin embargo, si me ato a una variable:

user=> (def apply-str (partial apply str)) 
#'user/apply-str 
user=> (-> ["1" "2" "3"] apply-str)  
"123" 

... el código funciona como era mi intención es. Supongo que son la misma cosa, pero aparentemente ese no es el caso. ¿Alguien puede explicar por qué esto es para mí?

Respuesta

6

-> es una macro, por lo que no tiene que seguir las reglas que esperaría en términos de aplicación. La macro transforma la fuente antes de que se evalúen los formularios. Pruebe macroexpandir los formularios:

user> (macroexpand '(-> ["1" "2"] (partial apply str))) 
(partial ["1" "2"] apply str) 

¿Qué está tratando de lograr aquí utilizando la macro '->'?

EDIT: Tenga en cuenta que:

user> ((partial apply str) ["1" "2"]) 
"12" 
+0

El código que estoy tratando de escribir es algo más complejo que eso. Esto es solo un ejemplo simplificado. Solo quiero entender mejor cómo funciona la macro '->'. :-) –

+0

Ah, tengo. De todos modos, ¿ves lo que está pasando aquí? –

+0

Sí, lo hago. ¡Gracias por tu respuesta! –

5

Usted no tiene que hacer eso en absoluto.

(->> ["1" "2" "3"] (apply str)) 

¿Por qué no hacer eso en su lugar?

4

La primera expresión, , se expande en:

(partial ["1" "2"] apply str) que básicamente significa:

crear una función de ["1" "2"] (que es también una función, ya que los vectores son funciones de claves de índice!) Con las Vars apply y str ya se suministraron como los primeros dos argumentos. Esta función se imprime como la extraña cadena #<core$partial...>. Solo cuando se invoque esta función obtendrá una IllegalArgumentException ya que los vectores solo toman un argumento entero, no dos argumentos Var.

+0

tenga en cuenta que Clojure es dinámico porque el hecho de que los vectores sean funciones no tiene importancia para este error. ("hello" "world" parcial) también devuelve una función, una función que siempre arroja. – cgrand

0

La macro -> agrega parens alrededor de apply-str en su segunda versión, por eso la macro se expande al código que termina llamando a su función. Mirar el código fuente para -> y se puede ver:

(defmacro -> 
    "Threads the expr through the forms. Inserts x as the 
    second item in the first form, making a list of it if it is not a 
    list already. If there are more forms, inserts the first form as the 
    second item in second form, etc." 
    ([x] x) 
    ([x form] (if (seq? form) 
       (with-meta `(~(first form) ~x [email protected](next form)) (meta form)) 
       (list form x))) 
    ([x form & more] `(-> (-> ~x ~form) [email protected]))) 

La parte pertinente es cuando se está tratando con dos argumentos, x y form. Si form es una secuencia, x se inserta como el segundo argumento en esa lista. De lo contrario, la macro pone form y x en una lista. Esto es para que pueda usar un símbolo simple como abreviatura de una lista que contiene un símbolo.

user> (macroexpand '(-> 123 (foo))) 
(foo 123) 
user> (macroexpand '(-> 123 foo)) 
(foo 123) 
1

La Macro -> Temas la expr a través de las formas como segundo argumento. En su caso, termina expandiéndose a: (partial ["1" "2"] apply str), creando una función parital basada en el vector.

pero que desea invocar una función parital basado en aplicar y str en la expr roscado y por lo tanto necesitan:

(-> ["1" "2"] ((partial apply str))) 

Bueno: este código i bastante confuso y no idiomática Clojure.