Fork me on GitHub
#core-async
<
2018-11-20
>
Garrett Hopper22:11:14

How can I create a channel in such a way that it combines multiple other channels and changes when a message is passed to only one of those channels (keeping the most recent value for the others)?

hiredman22:11:30

channels don't have "a" value

hiredman22:11:03

it sounds like maybe you want alts

noisesmith22:11:08

@ghopper that reminds me of dataflow systems where there's a "hot" input and multiple "cold" inputs

hiredman22:11:21

to select one value from multiple possible inputs

Garrett Hopper22:11:18

Right, I could use alt! / alts! in a go-loop and manually keep track of the most recent. I was just curious if core.async has this functionality already in a simpler way.

Garrett Hopper22:11:42

@noisesmith, yeah, I guess what I'm looking for is something along those lines. Have you seen this implemented with core.async before?

hiredman22:11:54

channels are not reference types that have a value when you deref them

Garrett Hopper22:11:18

Should I just be using atoms with watchers instead?

hiredman22:11:22

values flow through them, when you take a value from a channel, the value is gone

noisesmith22:11:55

@ghopper I could see using a go-loop where you call alts! on each loop, and call some f with all the values when the "hot" channel gets a value

noisesmith22:11:17

and use the loop bindings to preserve the most recent values seen from each channel

Garrett Hopper22:11:39

I suppose I could create some sort of macro to make creating this cleaner.

hiredman22:11:40

I dunno what you should be doing, but the words you are using when you talk about channels kind of lead me to believe you don't have a good mental model for them

Garrett Hopper22:11:44

I think that's the best bet at the moment.

hiredman22:11:50

throwing macros on top of a bad mental model for channels is not likely to result in something good

Garrett Hopper22:11:53

Well, I do think I'm perhaps using them in the wrong way. I do understand what they are/do though. I'm looking to have a single final value that's the result of multiple input channels. Whenever any of the inputs update, it should flow through to the output.

Garrett Hopper22:11:10

Heh, no, it probably wouldn't. ๐Ÿ˜›

hiredman22:11:01

"Whenever any of the inputs update, it should flow through to the output." seems to contradict "How can I create a channel in such a way that it combines multiple other channels and changes when a message is passed to only one of those channels (keeping the most recent value for the others)?"

hiredman22:11:39

it sounds like you are trying to do some kind of functional reactive programming thing

noisesmith22:11:01

right - the first description sounded like the hot input / cold input model from dataflow (capturing changes in cold inputs, firing some function with the most recent value for all the inputs hot and cold for a hot one), but the new description is much simpler to implement

Garrett Hopper22:11:22

Yeah, I wouldn't make any distinction between the inputs. If any of them updates, that should be passed on and 'trigger' updates of things that depend on it.

noisesmith22:11:40

Thinking about it more, I'd use a single hash-map with a key updated per channel in a go loop.

hiredman22:11:06

I wouldn't use core async at all

๐Ÿ‘ 4
Garrett Hopper22:11:15

@hiredman, what would you use?

hiredman22:11:40

I would keep a dependency graph, and traverse it

Garrett Hopper22:11:48

Ok, I may look into doing that. I may just need to try it both ways to see what the benefits are.

hiredman22:11:57

so you have a data structure like {:a {:deps [:b :c] :f ...}} would would be read as value :a is the result of applying function :f to the values of :b and :c

hiredman22:11:22

and you do a topo sort on the graph and traverse it building up values for each thing

Garrett Hopper22:11:16

Makes sense :thumbsup::skin-tone-2:

hiredman22:11:38

you could construct a graph of channels with go loops consuming from the channels to compute a value and emit it, but like, why? maybe if you want concurrency that makes sense (each f as like a little actor ), but you are likely better off building a single threaded graph traversal thing, and debugging your ideas, before trying to get it to run concurrently

Garrett Hopper22:11:18

Yeah, I think you're right. I'm not getting much benefit out of the route I'm going, and it can be done much simpler.