You can "capture" symbols from the surrounding context, making them
available to the body of your macros, the "tilde tick trick" is what
you're looking for there:
----------------------------------------
(defmacro deftransducer
[body]
`(fn [reducing-fn#]
(fn
([] (reducing-fn#))
([result#] (reducing-fn# result#))
([[~'guid-state ~'processed-events :as ~'result] ~'event]
~@body))))
----------------------------------------
now your macro's body has some implicitly defined variables available to
it called `guid-state` `processed-events` `result` and `event`
If you'd like to avoid the tilde trick and name your own variables, a
common pattern in Clojure is to pass in the binding form yourself as
part of the macro like so (assuming you don't care much about the first
two arities):
----------------------------------------
(defmacro deftransducer
[params body]
`(fn [reducing-fn#]
(fn
([] (reducing-fn#))
([result#] (reducing-fn# result#))
(~params ~@body))))
----------------------------------------
Now you can use this without being restricted to the same names every time:
-------------------------------------------------
(deftransducer [[my-state already-processed :as result] next-event]
...body goes here...)
----------------------------------------
Macros are great and lots of fun to write! But I think I'd echo what's
already been thrown out on this thread and suggest that you try to
recast your logic in terms of existing transducers or write a
higher-order function: something that takes a processing function and
returns a transducer.
Travis Daudelin <mailto:travis.daude...@gmail.com>
June 10, 2016 at 1:06 PMvia Postbox
<https://www.postbox-inc.com/?utm_source=email&utm_medium=sumlink&utm_campaign=reach>
Hi all!
I'm current working on a project where I am ingesting events off a
stream and processing them. There are many many steps involved in the
processing component, so I am choosing to write the steps as a series
of transducers (because, hey, they're super cool!). Here's the problem
though, after writing the first 2 processing steps I'm noticing that
all of them are going to look very similar:
||
(defn a-step-transducer
[]
(fn [reducing-fn]
(fn
([](reducing-fn))
([result](reducing-fn result))
([[guid-state processed-events :asresult]event]
;;step-specific logic
))))
Given how many steps I am planning to write, this is a ton of
boilerplate! So, my first thought was to use a macro to abstract away
all this boilerplate. Now, I have to admit that Clojure is my first
Lisp, so I'm really not sure I fully understand when or why to use
macros to do things. My current understanding is that macros are a
kind of "template" for code, so something like this where I don't want
to write the same function structure over and over seems like a decent
use case for macros (feel free to correct me if I'm totally off on
this). Here is my first attempt:
||
(defmacro deftransducer
[body]
`(fn [reducing-fn]
(fn
([] (reducing-fn))
([result] (reducing-fn result))
([[guid-state processed-events :as result] event]
~@body))))
The idea here being that in body I can reference the variables defined
by the macro like reducing-fn, result, event, etc. Of course, I
quickly found out that this doesn't work:
||
storm-etl.entry-processing>(deftransducer "something")
CompilerExceptionjava.lang.RuntimeException:Can't use qualified name
as parameter: storm-etl.entry-processing/reducing-function
Some quick googling tells me that the solution to this is to use
gensyms for these variable names, but that would defeat the whole
purpose of this because I want to be able to reference those variables
from within the code that I pass to my macro. Is this an appropriate
use case for macros or am I way off base? Is there an alternative
approach that would be recommended?
--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient
with your first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
---
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send
an email to clojure+unsubscr...@googlegroups.com
<mailto:clojure+unsubscr...@googlegroups.com>.
For more options, visit https://groups.google.com/d/optout.
--
Sent from Postbox
<https://www.postbox-inc.com/?utm_source=email&utm_medium=siglink&utm_campaign=reach>
--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
---
You received this message because you are subscribed to the Google Groups "Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.