34 comments

[ 3.4 ms ] story [ 71.2 ms ] thread
The problem is that generators are not that widely supported (yet). You could replace CSP with something like Bacon.js and likely achieve the same effect (don't have an example, but I'm researching the area for a new project)
Aren't generators part of Babel? As long as you target ES5 shouldn't you be able to use generators via Babel?
Generator functions are part of ES6/2015 and are supported by babel. But keep note that downgrading them to ES5 spec. includes a performance trade-off.
Take a look at http://cycle.js.org - it implements essentially the same concept using RxJS instead of csp and virtual-dom instead of React.
Except remember, RxJS is also a growing standard and the virtual-DOM Cycle.js uses has been tested to be a fair amount faster and robust than the one React has.

Then there is also Cycle's Model-View-Intent pattern and leading edge work on component integration, which is in line with W3C standards. Cycle's drivers also allow Cycle.js to integrate or target many options.

Things have been fragmented and Cycle.js seems to have brought the best together, representing a new and intelligent vortex of progress.

Before I took the time to understand what Cycle.js was about I was naive and thought React was it. I now understand how poorly it's reactivity has been implemented. On the other hand Cycle.js is fully reactive and has brought structure, flow and a sense of intelligence back to my app development.

For a light weight, ES5 style version, I have used a function generator (or factory, if you prefer). It keeps iteration state in its closure, and the resulting function updates it when its called. Your code calls generated function from then on. You can easily use arguments to reset the state, or to get something else to happen.

 	function gen_f() {

 		var count = 0;

 		function f() {
 			count += 1;
 			return count;
 		}
 		return f;
 	}
Probably you could use csp.take(channel) like in OP this way, too. I used this solution primarily because I couldn't figure out how generators handle arguments in iteration calls. My problem was to find a string that should be returned for a given index (where there was some complex rules on what string was active when) and to keep looping a list indefinitely. Generators seem to make things syntactically cleaner, but for me at least reasoning about them has been challenging in JS context.
They are widely supported: https://facebook.github.io/regenerator/

Yes, you can replace CSP with Rx style libraries. It's just a different kind of learning curve.

Personally I prefer CSP, as channels are a more primitive approach to writing concurrent applications.

CSP is like a library and Bacon/Rx are like frameworks.

This looks really fun way to develop React apps.

I just developed a React app, and managed to trip over state related problems at every stage. First with full state outside components, then within a top component, then I tried with a simple store type concept. Whenever I had to deal with async issues, I made a mistake with communicating ongoing state or getting React to notice changed state. I was waiting for Redux to go 1.0 (which it apparently did yesterday!).

I wonder how async updates, like network requests, to the model should work? Perhaps two channels, one for events from the components to what ever is handling requests for you (I just used D3, since I have some other uses for it), and then it can message the results via channel to what actually updates the model.

OP's example reminded me strongly of Mithril [1]. Though with addition of CSP channels to communicate changes, and explicit external render call, which Mithril allows also, but I don't remember having to use. It's clean and simple looking, and I like it. Now I got one more way to mess with my app state. And should I decide to use Mithril again on other projects, CSP seems like a worthy addition if it can be applied this easy.

[1] https://lhorie.github.io/mithril/

I have a small project that I poke at that uses Mithril + Kefir for a nice virtual DOM + FRP architecture. A few lines of glue code and I was good to go: https://git.dthompson.us/guix-web.git/blob/HEAD:/js/utils.js...

(pardon the self-signed cert)

Kefir looks interesting, thanks for the pointer!

Now if somebody makes async channel combinator so that I wouldn't had to build so much boilerplate for network requests. Be it direct callbacks or promises or the new fetch specification, control flow of async operations seems to require more than one channel and glue code in between. That seems to bend the paradigm a bit too much for what is essentially IO ops in my apps.

It probably won't scale well due to the number of ddp connections required, but I'm using Meteor and React for a side project. It's very pleasant to work with.
Why not have "incr" be a method on the model? Then the update() function with the big switch on "actionType" could be replaced with:

    model[action]()
I think this is a bad idea.

First with methods, you have mutable state, which I believe should be avoided. It causes a lot of problems for efficient rendering.

You could make some kind of wrapper, but I guess it's not worth the hassle to save a couple of characters.

Second, Action can cause complex writes that touch more than one model (or if you have one global model, multiple state slices). You probably want to have the write functions named independently, so they can be reused over multiple actions if necessary.

You don't avoid mutable state by doing "model.count += 1" in a separate update() function rather than a method on the model.

Both are functions that operate on the same data; the OO syntax is just a convenience that was invented exactly for the reason of avoiding endless switch statements in dispatching actions on a particular piece of data.

Doesn't the OO approach just move the work of the switch statement into the class declaration of the model? In practice, OO is about encapsulation, and FP is not. So it's probably not too surprising that the author chose not mix metaphors.

This is also modeled after an architecture in a statically typed language that expresses possible actions as a single union type, in which every possible type must be handled. There's no similar compile-time guarantee in JS, but a switch statements with constants is a reasonable approximation of the idea.

This is exactly the Same as Elm, without the type system to help you out.
Yeah, and without Signals to make things like mouse position transparent. I started using CSP in Cljs + React applications, but I find signals to be a better abstraction for UIs.
Agree. ReactJS was inspired by Elm as far as I know, Purescript has a framework purescript-signal that is inspired by Elm, ClojureScript has Zelkova that is inspired by Elm, and on it goes.

Makes it more and more tempting to just go straigth to the source and simply use Elm.

> Makes it more and more tempting to just go straigth to the source and simply use Elm.

Redux was inspired by Elm's update concept, not React.

I was on that train of thought too after using Redux had the side effect of giving me a conceptual understanding of how the update step works in Elm, but I found that "simply" really isn't the right word if your experience is primarily with imperative languages.

e.g. building an app starting from HTML5 history and routing built on top of it is just another API if you already know JavaScript, but it's an entire new set of concepts to learn if you're not au fait with functional programming, as I quickly discovered!

I think React predates Elm, and FRP has been around since 1995. React also isn't very FRP, it has more of the feeling of an immediate-mode GUI.
(FYI Wikipedia says Elm was released in 2012 and React in 2013, but that doesn't mean Facebook/Instagram weren't working on it before. Also Asana has been doing similar things since ~2009.
There isn't much new in React; they just got the timing right and went with a very solid design that was innovative enough. It really does look a lot like SOL and other immediate mode UI frameworks, with a touch of optimization for the web and some better identity management. But I don't get why people call it FRP though, its notion of components and composition is completely different from what originated in the original Hudak/Elliott work on Fran with higher order function compositions over signals (react is much more object based and much less functional). With Elm, the lineage is obvious, but for React it just seems like a misapplied label.
Higher level concepts in area so rife with incidental complexity like programming tend to get lost in the details of the implementation. Patterns and abstract concepts like FRP can only be understood by with implementation. Ideas tend to bend before working code, then again with an example app you enthusiastically write for your blog, and then again when someone bases her next project on that (not to mention HN discussions...).

I like to learn thing this way, and not care that much about what the alphabet soup entails. Try to find what is a proper JavaScript MVC framework. And then write the first one yourself ;)

I'm currently reading Clojure Reactive Programming, which differentiates from FRP using another term, CES for Compositional Event Systems, and goes to some length into history of these concepts, like higher order FRP, First Order FRP, Arrowized FRP, and of course Observer pattern and Data Flow programming. There is also Elm's creator's presentation at Strange Loop last year of the same topic:

https://www.youtube.com/watch?v=Agu6jipKfYw

I saw Evan's talk at Splash, and while it was good, I think the history is far more complex and nuanced than you can fit into a one hour keynote! When I hear CES I think component-entity systems (also popular in Clojure), but they have been rebranded as entity component systems (to not conflict with event systems), while Rx (Erik Meijer) would be more of where compositional event systems came from.

I have my own system that supports side effects with transactional semantics (see http://research.microsoft.com/en-us/um/people/smcdirm/apx/in... for the latest). I try to keep my bibliography straight since the questions will always be asked (how does your work compare to X?).

Is there any open-source classic app (ie talking with a server etc) in Elm? It looks quite interesting and one of my colleagues used it a bit some times ago (https://news.ycombinator.com/item?id=9068685) and liked it.
Hm, if you mean website, the elm-lang's site itself and the package search is written in elm. There is the usual todo app as well. Not sure about something like an chat application though.

I am planning to work through the [1] to see if I should switch from the clojure-script/reagent combo on my next side project :)

[1] https://github.com/evancz/elm-architecture-tutorial

The two challenges past this point are (a) making the components ignorant to the larger structure of the single state enabling things like component-local state and state representation independence and (b) getting creative with how to construct reducers composably so that various domain concerns are separated from one another in the construction of the core state.
How do you make sure that all your components have access to the same channel? In a typical setup you'd use something like webpack to import modules from separate files. Calling var channel = csp.chan() in each of these will create unique channels, doesn't it? The way I see it you'd need to pass this channel down to each component.
There is absolutely nothing related to FRP in this blog post, not even "composable event streams" for that matter. This is just using a CSP channel as a (global) event bus. It essentially replaces the (global) dispatcher with a CSP channel. This blog post's approach is essentially typical Flux and nothing else. And doesn't improve to make it more functional either, because both `onClick={this.clickHandler}` and `yield csp.put(channel, {actionType: 'incr'});` are imperative code.
Plus both redux and fluctuations work using immutable state and reducers rather than mutating actions.
I don't know js-csp (I prefer ES7 async/await + promises or streams) so correct me if I'm wrong, but the "csp.go" here isn't required since it's a single operation and the return value isn't used:

    csp.go(function*(){
      yield csp.put(channel, {actionType: 'incr'});
    });
I assume it's essentially the same as doing the following using async/await:

    (async function() {
        await csp.put(...);
    })();
Which is pointless.
I think the idea is to update the model asynchronously via put before rendering the new state via take. I'm not entirely sure (I don't know csp much) but I think using a single CSP channel makes that trivial, so you're always updating before rendering.

Would appreciate more insight and/or correction...

Right, but I presume csp.put() is asynchronous already, there's no point in wrapping it in csp.go().
How does this scale to multiple views, models, etc?