Search code examples
clojureclojure-contrib

Does Clojure have any functions similar to sow/reap from Mathematica?


Are there functions in the Clojure, which emulate the Mathemaica functions sow/reap? The main usage of sow and reap involve collecting expressions that were generated in the course of evaluation.

Example)

input in Mathematica: Reap[Sow[w = 2];w+=Sow[w^3];w=Sqrt[w + w^3]]

output: {Sqrt[1010], {{2, 8}}}

Giving intermediate results 2 and 8.


Solution

  • The wonderful thing about a homoiconic language like clojure is that you can define new syntaxes as you need them.

    (defmacro reap
      [& body]
      `(let [state# (atom [])
             ~'sow (fn sow [v#] (swap! state# conj v#) v#)]
         [(do ~@body) @state#]))
    

    For simplicity's sake I used jvm interop for math, instead of clojure.numeric-tower so we get floating point rather than exact output:

    user> (reap (let [w (sow 2)
                      w (+ w (sow (Math/pow w 3)))
                      w (Math/sqrt (+ w (Math/pow w 3)))]
                  w))
    
    [31.78049716414141 [2 8.0]]
    user> (= 31.78049716414141 (Math/sqrt 1010))
    true
    

    Edit: now that I see the docs for sow, it also has support for tagging and selecting by tag

    since this is clojure grabbing things by key is trivial, so I will just show a variant that makes the tags:

    (defmacro reap
      [& body]
      `(let [state# (atom {})
             ~'sew (fn sew [& [v# tag#]]
                     (swap! state# #(update-in % [tag#] conj v#)) v#)]
         [(do ~@body) @state#]))
    
    user> (reap (let [w (sew 2 :a)
                w (+ w (sew (Math/pow w 3)))
                w (Math/sqrt (+ w (Math/pow w 3)))]
            w))
    
    [31.78049716414141 {nil (8.0), :a (2)}]