Add chain, else* and cond* #71

Closed
wants to merge 4 commits into
from

Conversation

Projects
None yet
2 participants
@pyr
Contributor

pyr commented Nov 15, 2012

Three functions to help build more concise streams.

  • chain is a dummy function which helps you jump to a different
  • cond* acts as a cond-like equivalent in streams
  • else* is nice as the default operation for cond*
@aphyr

This comment has been minimized.

Show comment Hide comment
@aphyr

aphyr Dec 5, 2012

The example you give for chain is equivalent to a (let) or (def) binding. The advantage over def would be binding together several streams as one, but I don't think chain is the right word for it since the children are all at the same level. We could name it "all", but that might also be a useful predicate down the line. Could call it (dostream), by analogy with (do), but that implies invocation when there isn't any. Really it's a combinator, and needs a name that says so. "manifold" and "bifurcate" come to mind. Arrgh.

aphyr commented on 2ba0ebe Dec 5, 2012

The example you give for chain is equivalent to a (let) or (def) binding. The advantage over def would be binding together several streams as one, but I don't think chain is the right word for it since the children are all at the same level. We could name it "all", but that might also be a useful predicate down the line. Could call it (dostream), by analogy with (do), but that implies invocation when there isn't any. Really it's a combinator, and needs a name that says so. "manifold" and "bifurcate" come to mind. Arrgh.

This comment has been minimized.

Show comment Hide comment
@aphyr

aphyr Dec 5, 2012

I've wanted for some time to have a combinator called (pipe), which would pipe events between stages of streams like so:

(pipe [a1 a2] [b1] [c1 c2 c3])

         |-- a1 --|        |-- c1
events --|        |-- b1 --|-- c2
         |-- a2 --|        |-- c3

Naturally it would need to be a macro, since these streams only accept children through their arguments, but this gets really messy where (by) is involved, because (by) expects to be able to re-evaluate its children to create new threads of execution. Should it be able to? What would the semantic meaning of (pipe (by :service) (rate 5)) be? One rate, or many? Can we safely declare the behavior of by to be a black box as far as this combinator is concerned? Say what you will about the current macro mess, at least its behavior is well-defined, haha. I'm not even sure I can explain this idea to myself.

I wound up building (publish :some-channel) and (subscribe :some-channel ...) instead. I think those are a lot easier to understand conceptually. Do you think they solve the same problems (pipe) might solve?

aphyr replied Dec 5, 2012

I've wanted for some time to have a combinator called (pipe), which would pipe events between stages of streams like so:

(pipe [a1 a2] [b1] [c1 c2 c3])

         |-- a1 --|        |-- c1
events --|        |-- b1 --|-- c2
         |-- a2 --|        |-- c3

Naturally it would need to be a macro, since these streams only accept children through their arguments, but this gets really messy where (by) is involved, because (by) expects to be able to re-evaluate its children to create new threads of execution. Should it be able to? What would the semantic meaning of (pipe (by :service) (rate 5)) be? One rate, or many? Can we safely declare the behavior of by to be a black box as far as this combinator is concerned? Say what you will about the current macro mess, at least its behavior is well-defined, haha. I'm not even sure I can explain this idea to myself.

I wound up building (publish :some-channel) and (subscribe :some-channel ...) instead. I think those are a lot easier to understand conceptually. Do you think they solve the same problems (pipe) might solve?

This comment has been minimized.

Show comment Hide comment
@aphyr

aphyr Dec 5, 2012

I like (cond_), but I think we can do slightly better than the explicit (fn) predicates by building direct stream analogues to cond and condp. Neither cond nor condp needs else_, which will simplify matters a bit.

(scondp < :metric
  50 (with :state "ok" index)
  75 (with :state "warning" index)
  95 (with :state "critical" index)
  (with :state "oh no" index email))

aphyr replied Dec 5, 2012

I like (cond_), but I think we can do slightly better than the explicit (fn) predicates by building direct stream analogues to cond and condp. Neither cond nor condp needs else_, which will simplify matters a bit.

(scondp < :metric
  50 (with :state "ok" index)
  75 (with :state "warning" index)
  95 (with :state "critical" index)
  (with :state "oh no" index email))
@pyr

This comment has been minimized.

Show comment Hide comment
@pyr

pyr Dec 5, 2012

Contributor

@aphyr,

Thanks for the review.

First about cond_, like your cond and condp, but I still think there should be a generic cond_ when you
want arbitrary fns, I meant to build cond on top of cond*, i can do that in a later PR if you want.

As for pipe, I like the pipeline idea, a lot. This is what i wanted to express with chain and how I am using it.
What I do that seems harder to express with a pipeline is skipping some steps which jumping allows me to do.

I'm not sure pubsub is as natural to read so I would be wary of using that.

I'm a bit worried about macro hell to be honest, and I think finding a way to decouple the predicate and filter funcs from call-rescue would be nice before moving on with this work. maybe by having streams wrap each of its forms, what do you think ?

Contributor

pyr commented Dec 5, 2012

@aphyr,

Thanks for the review.

First about cond_, like your cond and condp, but I still think there should be a generic cond_ when you
want arbitrary fns, I meant to build cond on top of cond*, i can do that in a later PR if you want.

As for pipe, I like the pipeline idea, a lot. This is what i wanted to express with chain and how I am using it.
What I do that seems harder to express with a pipeline is skipping some steps which jumping allows me to do.

I'm not sure pubsub is as natural to read so I would be wary of using that.

I'm a bit worried about macro hell to be honest, and I think finding a way to decouple the predicate and filter funcs from call-rescue would be nice before moving on with this work. maybe by having streams wrap each of its forms, what do you think ?

@aphyr aphyr closed this Dec 6, 2012

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment