On Nov 23, 9:56 pm, James Reeves <
weavejes...@googlemail.com> wrote:
> On Nov 23, 11:58 pm, Justin Giancola <
justin.gianc...@gmail.com>
> wrote:
>
> > Neat. I noticed that you're forcing the arg lists into vectors in both
> > make-maps and in stubfn. Since they're not being manipulated at all,
> > you could just as easily leave them as seqs and everything will still
> > work.
>
> The reduce is a good idea, but your method of quoting the hash doesn't
> evaluate the return value:
>
> user=> (stub [(f 1 2) (+ 1 2)] (f 1 2))
> (+ 1 2)
>
> Whilst with the original:
>
> user=> (stub [(f 1 2) (+ 1 2)] (f 1 2))
> 3
Oops--when I realized the arg list hash keys were being evaluated
during stub function creation I should have addressed that directly
instead of just quoting the entire hash!
> This was why I turned it into a vector. It seemed the easiest way of
> getting a hash that I didn't have to quote, but whose values would be
> correctly evaluated.
Using vectors will work since they're self-evaluating, but you can
also prevent the unwanted evaluation by wrapping them in quote forms
as the hash is being assembled:
(defmacro stub [stubs & body]
(let [stub-maps
(reduce (fn [acc [[f & args] res]]
(assoc-in acc [f `'~args] res))
{}
(partition 2 stubs))]
`(binding
[~@(mapcat (fn [[fname fhash]]
`(~fname (fn [& args#] (~fhash args#))))
stub-maps)]
~@body)))
This way when the stub functions are created you end up with list
literals for keys and correctly evaluated values.
However, quoting the arg lists this way necessitates that calls to the
stub functions have arg lists identical to those used to generate the
stubs.
i.e.
user=> (stub [(f 1 2) (+ 1 2)] (f 1 2))
3
but
user=> (stub [(f 1 (+ 1 1)) (+ 1 2)] (f 1 2))
nil
So, you need to evaluate all of the args independently when building
the list literals, possibly with:
(defmacro stub [stubs & body]
(let [stub-maps
(reduce (fn [acc [[f & args] res]]
(assoc-in acc [f `(list ~@args)] res))
{}
(partition 2 stubs))]
`(binding
[~@(mapcat (fn [[fname fhash]]
`(~fname (fn [& args#] (~fhash args#))))
stub-maps)]
~@body)))
I'm not sure this is quite as easy to follow, but I'd prefer to avoid
proxying all of the arg lists through vectors just because they're
self-evaluating.
Justin