2010-11-03 3 views
6

Je pensais que je posterais cela comme je l'ai eu à travailler par devinettes sans une réelle compréhension de ce qui se passe et je pensais que cela pourrait être utile si quelqu'un l'a expliqué.Formes destructrices et Compojure?

Je comprends comment obtenir à un élément du: params carte dans un gestionnaire Compojure:

(GET "/something" [some_arg] "this is the response body") 

ou

(GET "/something" {{some_arg "some_arg"} :params} "this is the response body") 

bien que je ne comprends pas tout à fait ce que la partie {some_arg "some_arg"} fait :(

Je voulais également accéder à la partie :remote-addr de la demande, ainsi que some_arg et je me suis retrouvé avec

(GET "/something" {{some_arg "some_arg"} :params ip :remote-addr} 
    (do-something-with some_arg ip)) 

Alors, je reçois que les chaînes et non cotées some_argip sont les noms des variables auxquelles je veux les valeurs liées, mais la carte ci-dessus n'est pas une carte Clojure valide. Comment ça marche? J'obtiens aussi que ceci est évalué par rapport à la carte de demande de Ring (qui est fournie par la macro defroutes) mais l'expression ci-dessus n'est pas une fonction ou une définition de macro, donc comment peut-elle 'exister' comme une expression valide dans mon code? Y at-il une sorte de suspension des règles normales pour les arguments macro? J'ai été incapable de trouver une définition de la syntaxe des formes destructrices compréhensibles pour ce non-Lisp'er.

+1

J'ai raté le fait que GET est une macro. Expliqué dans la réponse ci-dessous ... – edoloughlin

Répondre

3

La carte est une carte de déstructuration valide. Dans n'importe quel endroit où vous liez des noms, vous pouvez utiliser la déstructuration. Vous pouvez faire la même chose dans un let, comme ceci:

user=> (let [{{some-arg "some_arg"} :params ip :remote-addr} {:remote-addr "127.0.0.1" :params {"some_arg" "some_value"}}] [ip some-arg]) 
["127.0.0.1" "some_value"] 

J'ai écrit un post sur la carte destructuration dans le contexte des arguments nommés, mais il applique ici. Vous trouverez peut-être ce utile: Clojure - named arguments

Il y a beaucoup de messages de blog démontrant destructuration, y compris un this. Je ne suis pas sûr de savoir lequel serait un endroit canonique pour apprendre. Je ne prétends pas savoir exactement ce que fait la carte avec cette carte sous le capot, mais je présume qu'elle la jette dans un let ou quelque chose de similaire comme je l'ai démontré plus haut. GET est une macro, donc il n'a pas à évaluer la carte que vous lui transmettez, c'est pourquoi vous n'obtiendrez pas d'erreur à moins de l'avoir évalué.

user=> (defmacro blah [m]) 
#'user/blah 
user=> (blah {a "b" c "d"}) 
nil 
user=> (defn blah [m]) 
#'user/blah 
user=> (blah {a "b" c "d"}) 
java.lang.Exception: Unable to resolve symbol: a in this context (NO_SOURCE_FILE:9) 

Sous le capot, la magie arrive à cette carte et il est transmis à une fonction appelée déstructurant qui fait la magie déstructurant.

Il n'y a pas vraiment de choses spéciales à faire ici, hormis une macro normale/une forme spéciale foo et une évaluation retardée.

1

Destructing se déroule dans une forme contraignante et pour carte déstructurer le var à être lié est à gauche, et la clé est sur la droite:

 
user=> (let [{a :foo} {:foo :bar}] 
user=* a) 
:bar 

Compojure fait une forme de liaison dans les coulisses , de sorte que la forme de carte déstructurant que vous utilisiez ci-dessus est effectivement transformé en quelque chose comme:

 
(let [{{some_arg "some_arg"} :params} request] 
    ...) 

request est une carte fournie implicitement.

La version vectorielle (par exemple [some_arg]) est une alternative qui se lie simplement à la carte :params contenue dans la requête.