1

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.

sunspots
  • 1,047
  • 13
  • 29
  • Could you provide an example? I am thinking of something like `reductions` but I am not sure if that is what you mean. – ponzao Nov 13 '13 at 20:44
  • You should probably include more details about the functions; not all of us use Mathematica. – Dogbert Nov 13 '13 at 20:44

1 Answers1

10

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)}]
noisesmith
  • 20,076
  • 2
  • 41
  • 49
  • and now I see that the tagged items are in reverse order on exit so they need the vals in the map reversed at exit... but this should be good for a proof of concept even if a few bugs / lacking functionality remain – noisesmith Nov 14 '13 at 01:16
  • Why do you use `~'sow` in the macro's `let` bindings? Isn't that equivalent to just plain `sow` without the unquote? – Nathan Davis Nov 16 '13 at 06:39
  • 1
    quasiquote creates namespaced bindings. A way around this is to gensym (by appending # to the name), but if you use a gensym, the user won't actually know the symbol to use (that's the point of gensym). The only way to use a simple unnamespaced symbol in a let in a macro is with ~' – noisesmith Nov 18 '13 at 17:44