質問

私はClojureの中にマッピングされた機能の進行状況を監視する必要がありますどのように?

私は頻繁に物事が行っているどこまで示すためにしょっちゅうメッセージを印刷する命令型言語、例えば内のレコードを処理する場合すべての1000年の記録を報告します。基本的に、これは、ループの繰り返しをカウントされます。

私は、レコードの私のシーケンス上の機能をマッピングしていますどこ私はClojureの中でこれに取ることができるのアプローチと思いまして。この場合、メッセージを印刷(さらに進歩のカウントを維持する)に実質的な副作用であるように見える。

私は今のところ出ていることのように見えます

(defn report
  [report-every val cnt]
  (if (= 0 (mod cnt report-every))
    (println "Done" cnt))
    val)

(defn report-progress
  [report-every aseq]
  (map (fn [val cnt] 
          (report report-every val cnt)) 
       aseq 
       (iterate inc 1)))

user> (doall (report-progress 2 (range 10)))
Done 2
Done 4
Done 6
Done 8
Done 10
(0 1 2 3 4 5 6 7 8 9)

は、この効果を達成するのが他の(良い)方法はありますか?

すべての落とし穴は、私がやっているものの中にありますか? (私は怠惰を維持し、例えば頭を保持していないと思う。)

役に立ちましたか?

解決

Clojureの素晴らしいところは、あなたがデータそのものの代わりに、コンピューティングを行うコードへの報告を添付することができます。これは、あなたがこれらの論理的に異なる部分を分離することができます。ここで私は、私はちょうど約すべてのプロジェクトで使用見つける私misc.cljからのチャンクがあります:

(defn seq-counter 
  "calls callback after every n'th entry in sequence is evaluated. 
  Optionally takes another callback to call once the seq is fully evaluated."
  ([sequence n callback]
     (map #(do (if (= (rem %1 n) 0) (callback)) %2) (iterate inc 1) sequence))
  ([sequence n callback finished-callback]
     (drop-last (lazy-cat (seq-counter sequence n callback) 
                  (lazy-seq (cons (finished-callback) ())))))) 

、あなたのデータを中心にレポーターをラップして、処理機能に結果を渡します。

(map process-data (seq-counter inc-progress input))

他のヒント

私はおそらく、エージェントに報告を行います。このような何かます:

(defn report [a]
  (println "Done " s)
  (+ 1 s))

(let [reports (agent 0)]
  (map #(do (send reports report)
            (process-data %))
       data-to-process)

私は多分何かがすでにあるかどう見てclojure.contribのドキュメントを参照するには良いでしょう、それを行うのいずれかの既存の方法を知りません。一方で、私はあなたの例を見て、少しそれをクリアしてきました。

(defn report [cnt]
  (when (even? cnt)
    (println "Done" cnt)))

(defn report-progress []
  (let [aseq (range 10)]
    (doall (map report (take (count aseq) (iterate inc 1))))
    aseq))

この例では、あまりにもシンプルであっても、正しい方向に向かっています。これは、私にあなたのレポート進行機能のより一般化されたバージョンについての考えを与えました。この機能は、マップのような機能、マッピングする機能、レポート機能やコレクションのセット(または減らすテストするためのシード値とコレクションを)取るます。

(defn report-progress [m f r & colls]
  (let [result (apply m
                 (fn [& args]
                   (let [v (apply f args)]
                     (apply r v args) v))
                 colls)]
    (if (seq? result)
      (doall result)
      result)))

配列?一部しかない削減で使用するためにあり 必ずしもシーケンスを返します。この機能により、私たちはあなたを書き換えることができます このような例:

user> 
(report-progress
  map
  (fn [_ v] v)
  (fn [result cnt _]
    (when (even? cnt)
      (println "Done" cnt)))
  (iterate inc 1)
  (range 10))

Done 2
Done 4
Done 6
Done 8
Done 10
(0 1 2 3 4 5 6 7 8 9)

フィルタ機能をテスト

user> 
(report-progress
  filter
  odd?
  (fn [result cnt]
    (when (even? cnt)
      (println "Done" cnt)))
  (range 10))

Done 0
Done 2
Done 4
Done 6
Done 8
(1 3 5 7 9)

とでも減らす機能:

user> 
(report-progress
  reduce
  +
  (fn [result s v]
    (when (even? s)
      (println "Done" s)))
  2
  (repeat 10 1))

Done 2
Done 4
Done 6
Done 8
Done 10
12
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top