Существует ли стандартная функция "foreach" в Clojure?

Clojure> (doc foreach)
Unable to resolve var: foreach in this context

Clojure> (doc map)
-------------------------
clojure.core/map
([f coll] [f c1 c2] [f c1 c2 c3] [f c1 c2 c3 & colls])

Конечно, я могу использовать "карту" для имитации "foreach", но карта всегда возвращает nil, что делает выход уродливым в следующей функции:

(defn div618 [p1 p2]
    (let [ratio [0.,0.191,0.236,0.382,0.5,0.618,0.809,1.]
          price (fn [r] (if (<= p1 p2) (+ p1 (* (- p2 p1) r)) (- p1 (* (- p1 p2) r))))]

    (if (<= p1 p2)
        (**map** #(println (format "-------%.3f   %.2f-------" %1 (price %1))) (reverse ratio))
        (**map** #(println (format "-------%.3f   %.2f-------" %1 (price %1)))  ratio))))

С уважением!

Ответы

Ответ 1

Я думаю, что doseq может быть тем, что вы ищете:

(doseq [i [0 1 2 3]] (println i))

Однако это все равно вернет nil - все формы в Clojure будут оцениваться до некоторого значения; нет эквивалента Common Lisp (values).

Ответ 2

Вы можете использовать дозу или doall. Ниже приведен пример использования doall.

(defn div618 [p1 p2]
    (let [ratio [0.,0.191,0.236,0.382,0.5,0.618,0.809,1.]
          price (fn [r] (if (<= p1 p2) (+ p1 (* (- p2 p1) r)) (- p1 (* (- p1 p2) r))))]

    (doall (map #(println (format "-------%.3f   %.2f-------" %1 (price %1))) (if (<= p1 p2) (reverse ratio) ratio)))))

Вы также можете отделить печать от вычисления функции следующим образом:

(defn div618 [p1 p2]
    (let [ratio [0.,0.191,0.236,0.382,0.5,0.618,0.809,1.]
          price (fn [r] (if (<= p1 p2) (+ p1 (* (- p2 p1) r)) (- p1 (* (- p1 p2) r))))]

    (map (fn [x] [x (price x)]) (if (<= p1 p2) (reverse ratio) ratio))))

(doall (map #(println (format "-------%.3f   %.2f-------" (first %1) (last %1))) (div618 1 2)))

Ответ 3

Каркас

используется для применения функции f к каждому элементу seq, в вашем случае ваш отпечаток, который возвращает nil, поэтому вы получаете промежуточное количество нулей, которое вы затем выбрасываете. Когда вам нужны побочные эффекты, такие как печать, вы используете дозу.

Clojure не имеет единой карты формы foreach, уменьшает фильтр и т.д. технически все это формы foreach, все они делают что-то для каждого элемента в seq. Также карта ленив, ваш пример будет напечатан только в repl, потому что repl заставляет ленивый seq реализовать их, если вы упакуете это в банку, он ничего не сделает.

Ответ 6

(defn div618 [p1 p2]
  (let [ratio [0.000 0.191 0.236 0.382 0.500 0.618 0.809 1.000]            
        price #(if (<= p1 p2)
                 (-> p2 (- p1) (* %) (+ p1))
                 (-> p1 (- p2) (* %) (- p1)))
        print-all #(doseq [item %]
                     (printf "-------%.3f   %.2f-------\n" item (price item)))]
    (if (<= p1 p2)
      (print-all (reverse ratio))
      (print-all ratio))))