2014-07-21 8 views
5

Clojure's for makro akceptuje dwa argumenty: sekwencję form wiążących i wyrażenie ciała. Jako takie, jeśli chcę zrobić wiele rzeczy w pętli, muszę zawijać wiele wyrażeń w bloku do, aby uczynić je pojedynczym wyrażeniem.Dlaczego Clojure's for macro akceptuje tylko jedno wyrażenie ciała?

Porównaj:

(doseq [a (range 3)] 
    (prn 'a a) 
    (inc a)) 

do:

(for [a (range 3)] 
    (prn 'a a) 
    (inc a)) 

W doseq działa zgodnie z oczekiwaniami. for narzeka:

clojure.lang.ArityException: Wrong number of args (3) passed to: core/for 

Moje pytanie brzmi, dlaczego nie to działa? Dlaczego projektanci (i) Clojure nie dopuszczają wielokrotnych wyrażeń "ciała" w pętli for, tak jak w przypadku doseq i when? To nie jest tak, jakby istniała jakakolwiek semantyczna dwuznaczność, prawda?

+1

Jedną z dużych różnic jest to, że 'for' jest leniwy, natomiast' doseq' (głównie w celu wywoływania efektów ubocznych) nie jest. 'when' ocenia swoje ciało w postaci niejawnego' do'. Zobacz także http://stackoverflow.com/q/4725417 –

Odpowiedz

13

Clojure's for nie jest pętlą, jest leniwym rozumieniem listy. Ponieważ zwracana jest tylko wartość ostatniego wyrażenia w ciele (niejawnego) do, jakiekolwiek inne wyrażenia musiałyby istnieć jedynie w przypadku skutków ubocznych. Wykonywanie efektów ubocznych jest zadaniem doseq, dlatego ma domyślne do. To, że for nie powinno być przypomnieniem, czy naprawdę chcesz efektów ubocznych w swojej leniwej sekwencji? Chociaż istnieją uzasadnione powody, aby to zrobić, należy zadbać o to, aby te efekty uboczne były wykonywane, gdy tego chcesz.

(def foo (for [a (range 32)] 
      (do 
      (prn (str "a is " a)) 
      (inc a)))) 

(take 1 foo) 
;=> 
    ("a is 0" 
    "a is 1" 
    ... 
    "a is 31" 
    1) ; <= the return value 

(take 10 foo) 
;=> 
    (1 2 3 4 5 6 7 8 9 10) ; aw, no side effects this time 
+0

Dobra odpowiedź, chociaż myślę, że część chrupiąca na końcu to głównie czerwony śledzia, a nie wyjaśnione wystarczająco dobrze, aby i tak być przydatne. – amalloy

+0

Ach, to ma sens. Dzięki za wyjaśnienie. –