2010-02-22 7 views
28

J'ai une séquence (foundApps) retournée par une fonction et je veux mapper une fonction à tous ses éléments. Pour une raison quelconque, apply et count travail pour la sequnece mais map ne compte pas:Clojure par rapport à la carte

(apply println foundApps) 
(map println rest foundApps) 
(map (fn [app] (println app)) foundApps) 
(println (str "Found " (count foundApps) " apps to delete")))) 

Prints:

{:description another descr, :title apptwo, :owner jim, :appstoreid 1235, :kind App, :key #<Key App(2)>} {:description another descr, :title apptwo, :owner jim, :appstoreid 1235, :kind App, :key #<Key App(4)>} 
Found 2 apps to delete for id 1235 

Alors apply semble fonctionner heureusement pour la séquence, mais map ne fonctionne pas. Où suis-je stupide?

Répondre

31

Vous êtes probablement victime de la paresse de map. (map produit une séquence paresseuse qui n'est réalisée que lorsqu'un code utilise réellement ses éléments et même alors la réalisation se fait en morceaux, de sorte que vous devez parcourir toute la séquence pour vous assurer que tout a été réalisé.) Essayez d'utiliser l'expression map dans un dorun:

(dorun (map println foundApps)) 

de plus, comme vous le faites juste pour les effets secondaires, il pourrait être plus propre à utiliser doseq à la place:

(doseq [fa foundApps] 
    (println fa)) 

Notez que (map println foundApps) devrait fonctionner très bien au REPL; Je suppose que vous l'avez extrait de quelque part dans votre code où il n'est pas forcé. Il n'y a pas une telle différence avec doseq qui est stricte (c'est-à-dire pas paresseux) et marchera ses séquences d'arguments pour vous en toutes circonstances. Notez également que doseq renvoie nil comme sa valeur; c'est seulement bon pour les effets secondaires. Enfin, j'ai ignoré le rest de votre code; vous pourriez avoir voulu dire (rest foundApps) (sauf si c'est juste une faute de frappe).

Notez également que (apply println foundApps) imprimera tous les foundApps sur une ligne, alors que (dorun (map println foundApps)) imprimera chaque membre de foundApps sur sa propre ligne.

+3

Y a-t-il une différence entre 'dorun' et' doall'? –

8

Une petite explication pourrait aider. En général, vous utilisez apply pour splater une séquence d'éléments dans un ensemble d'arguments à une fonction. Donc appliquer une fonction à certains arguments signifie simplement les passer en arguments de la fonction, dans un seul appel de fonction.

La fonction de carte fera ce que vous voulez, créer un nouveau seq en branchant chaque élément de l'entrée dans une fonction, puis en stockant la sortie. Il le fait paresseusement, donc les valeurs ne seront calculées que lorsque vous itérez réellement sur la liste. Pour forcer cela, vous pouvez utiliser la fonction (doall my-seq), mais la plupart du temps vous n'aurez pas besoin de faire cela.

Si vous devez effectuer une opération immédiatement parce qu'elle a des effets secondaires, comme l'impression ou l'enregistrement dans une base de données ou autre, vous utilisez généralement doseq.

Donc, pour ajouter "foo" à toutes vos applications (en supposant qu'ils sont des chaînes):

(carte (fn [app] (app str "foo")) trouvés-apps)

ou en utilisant la shorhand pour une fonction anonyme:

(carte # (str% "foo") trouvés-apps)

Faire la même chose, mais immédiatement l'impression peut être fait avec l'une de ces:

(Doall (carte # (println%) trouvés-apps))

(doseq [app trouvés-apps] (println app))

13

J'ai une explication simple qui manque à ce poste. Imaginons une fonction abstraite F et un vecteur. Ainsi,

(apply F [1 2 3 4 5]) 

se traduit

(F 1 2 3 4 5) 

ce qui signifie que F doit être au mieux variadique cas.

Alors que

(map F [1 2 3 4 5]) 

se traduit

[(F 1) (F 2) (F 3) (F 4) (F 5)] 

ce qui signifie que F doit être une seule variable, ou au moins se comportent de cette façon.

Il existe quelques nuances sur les types, car map renvoie en réalité une séquence paresseuse au lieu du vecteur. Mais par souci de simplicité, j'espère que c'est pardonnable.

+0

Merci pour la réponse conceptuelle simple! – JaKXz

+3

Grande explication d'appliquer vs carte. Il y a un nom pour ce qui s'applique dans d'autres langages de programmation dynamiques, cela s'appelle splatter ou déballer. – blushrt

+0

Ma vie est plus simple maintenant. Je vous remercie (: – stryku

Questions connexes