在clojure中定义`fori`宏/函数

时间:2014-05-23 21:45:40

标签: clojure

我希望能够遍历集合,但是使用该循环维护计数器。我设法创造了例如。

(for [[email i] (map vector emails (range))]
  ...)

要做到这一点,但理想情况下,我更喜欢fori宏(除非功能可行,但我的直觉说它必须是一个宏)才能让我做同等的事情

(fori [email i emails]
  ...)

(fori [[email i] emails]
  ...)

我没有使用宏的经验,并且查看for宏的来源,看起来非常令人生畏。有什么帮助吗?

Super-cool将是一个遵循for语法并允许例如

的宏
(fori [email i emails
       line j (lines email)]
  ...)

2 个答案:

答案 0 :(得分:2)

您可以编写一个扩展为for的宏,但我并不是真的相信它有多重要。正是出于这个目的,有许多内置函数,fori语法并不能很好地读取。至少看起来应该是

(fori [[email i] emails, 
       [line j] (lines email)]
  ...)

但如果你真的想按照你说的那样写出来,那肯定不是不可能的:

(defmacro fori [bindings body]
  (letfn [(clauses [bindings]
            (lazy-seq
              (cond (empty? bindings) ()
                    (keyword? (first bindings)) (concat (take 2 bindings)
                                                        (clauses (drop 2 bindings)))
                    :else (let [[name index value] (take 3 bindings)]
                            (list* [index name] `(map-indexed vector ~value)
                                   (clauses (drop 3 bindings)))))))]
    `(for [~@(clauses bindings)]
       ~body)))

user> (macroexpand-1 '(fori [email i xs, 
                             :when (even? i)
                             line j (lines email)]
                        [i line]))
(for [[i email] (map-indexed vector xs)
      :when (even? i)
      [j line] (map-indexed vector (lines email))]

  [i line])

答案 1 :(得分:0)

(defn fori [coll]
  (map-indexed (fn [idx itm] [idx itm]) coll))

可能是你想要的。 e.g。

(fori [:a :b :c :d])

产生

([0 :a] [1 :b] [2 :c] [3 :d])

顺便说一句,因为它不是循环,而是创建列表理解。如果你想在循环中做一些副作用,你应该考虑剂量。