2010-07-15 4 views
6

J'ai un code comme celui-ci. Je peux lancer ceci dans repl mais je ne peux pas partir de la ligne de commande. Je suppose que j'ai un problème d'évaluation paresseux.Problème d'évaluation paresseux


; items.clj 

(def items (ref [])) 

(defn init-items [] 
    (map 
    #(dosync 
     (alter items conj %)) 
    ["foo" "bar" "baz" ])) 

(init-items) 
(println (first @items)) 

$ java -jar clojure.jar items.clj 
$ nil 

Cordialement.

Répondre

4

L'a obtenu!

solution

Clojure n'est pas motivé pour exécuter la fonction map dans init-items parce qu'il n'y a pas de résultat retourné. J'ai enveloppé cela dans un doall pour forcer l'exécution, et hop.

+0

je travaillais. Merci beaucoup. – Osman

+3

En fait 'dorun' est mieux adapté à ce cas (' doall' tient sur la tête du seq qu'il enveloppe et le retourne, alors que 'dorun' le rejette pas à pas et retourne finalement' nil' - donc il est mieux adapté à code à effets secondaires). –

+0

@Michal: Vous avez absolument raison, bien sûr. Je me suis un peu amusé avec Clojure mais je n'ai jamais atteint un niveau de compétence élevé, et maintenant, malheureusement, même cela commence à rouiller. Merci pour la correction! –

4

Quelques alternatives:

Si vous voulez juste ajouter un tas d'éléments à une collection tenue à Aref, à partir d'une transaction par article et conj les qu'ING séparément un peu inutile. Au lieu de cela, vous pouvez faire

(defn init-items [] 
    (dosync (alter items into ["foo" "bar" "baz"]))) 

Si vous avez une raison de le faire de façon un article-par-étape, je pense que l'approche la plus idiomatiques et pratique serait actuellement d'utiliser doseq:

(defn init-items [] 
    (doseq [item ["foo" "bar" "baz"]] 
    (dosync (alter items conj item)))) 

(Ou vous pouvez déplacer envelopper l'ensemble doseq dans un dosync et ne pas utiliser dosync dans le corps du doseq.)