One thing I’ve always struggled with is how to model clojurescript UI DOM components (ie an arbitrary DOM tree) using core async. And I tend to come back to attempting this every few months :)
How do I expose from a UI component the need to trigger dom events on internal elements, and the output of events triggered on internal elements?
It seems like the options are
Have a general input and output chan for each ui component. Could either wrap the events and triggers in a way that meets my needs (IE [::focus]
could trigger the dom .focus
event on an internal element. And something like [::query-input “query string”] could be put on the output chan. One problem with this is the the events sometimes in theory represent separate async processes (ie a mouseover event could occur simultaneously as a click event), but it’s more rare for this to be relevant.
Have a specific input/output chan for each needed event type. Ie have the component have a :query-input-chan
which outputs changes to the internal query input element. Expose as many chans that are needed for each component.
I’m working on an emacs-like editor thing where there are windows and buffers in a windowing system where the buffers can be basically anything (ie a text editor, file picker, repl, etc). Each buffer is sort of it’s own entities and has its own lifecycle, dependencies and sub-processes. I haven’t found this to fit will with the reframe global message bus style, but I haven’t been satisfied with my attempts at either of the above approaches in isolated components either.
Any general tips/tricks or thoughts about this type of thing?
hi all, im struggling trying to understand how to apply a stateful transducer to a core.async channel
specifically, im interested in using this lib: https://github.com/MastodonC/kixi.stats
i have a stream of data with messages like {:duration 34.56}
and I want to execute a summary on them, getting the result once the stream closes
any guidance appreciated
you can't
transducers on channels do run a completion step, but the result of the completion step is ignored
(the channel is closed nowhere to put it)
you may want something like async/transduce (a transducer over a channel) instead of a transducer passed to a channel
(a transducer in a channel?)
that makes some sense
actually now that I look at async/trasnduce, I think I get what you are saying
let me try
(ty)
@hiredman My first attempt looks like this
(async/transduce :duration kixi/summary ch)
this of course doesnt work since its an arity-4 function
but im not clear what I need for init
it looks like kixi/summary might be a reducing function, not a transducer
e.g. you would apply it like (reduce summary collection-of-numbers)
async/transduce takes four arguments, xform, f, init, and ch
xform is a transducer
f is a reducing function
init is the initial value for the accumulator when reducing
ch is the source of data
right...if I run it like this
(transduce identity kixi.stats.core/summary [1 2 3])
=> {:min 1.0, :q1 1.25, :median 2.0, :q3 2.75, :max 3.0, :iqr 1.5}
it makes sense to me
im not sure how to map that to async/transduce
1:1 you transduce just requires an initial value, which you might be able to get by calling summary with 0 arguments
i guess this is closer to my use case
(transduce (map :duration) kixi.stats.core/summary [{:duration 1.0} {:duration 2.0} {:duration 3.0}])
=> {:min 1.0, :q1 1.25, :median 2.0, :q3 2.75, :max 3.0, :iqr 1.5}
if you look at the docstring for transduce:
clojure.core/transduce
([xform f coll] [xform f init coll])
reduce with a transformation of f (xf). If init is not
supplied, (f) will be called to produce it. f should be a reducing
step function that accepts both 1 and 2 arguments, if it accepts
only 2 you can add the arity-1 with 'completing'. Returns the result
of applying (the transformed) xf to init and the first item in coll,
then applying xf to that result and the 2nd item, etc. If coll
contains no items, returns init and f is not called. Note that
certain transforms may inject or skip items.
it can also take an init, and if an init is not provided it calls f with no arguments to produce one
async/transduce just doesn't do that step, so you have to do it yourself
i gotcha
let me try that
@hiredman that was it!
thank you
this worked:
(async/transduce (map :duration) summary (summary) ch)