7 ms·
As the author says, there's quite a lot of imperative stuff in this design. I'm still on the fence about whether that's the best way to build large applications
by jarrett 12y ago
As the author says, there's quite a lot of imperative stuff in this design. I'm still on the fence about whether that's the best way to build large applications with GUIs, network access, etc.
With the imperative approach, you make liberal use of the IO monad. There's a lot of explicit reading from and writing to mutable storage. If you're doing this approach right, you mostly just use the IO monad for actual IO and threading; most of the real logic of the program is kept pure. This approach has the advantage of being familiar. And more importantly, it just plain works. It's how I tend to do things.
Yet I can't help but wonder if there's a better way. The above approach, while comfortable, leaves me with a bad taste in my mouth, like I'm somehow fighting against the language. I've often heard functional reactive programming (FRP) described as the best alternative. Though I remain skeptical. I'd be interested in opinions about the future of FRP.
- steveklabnik 12y agoAs FRP becomes more and more 'normal' in JavaScript land, I think it has a bright future.
- jarrett 12y agoAre you referring to the various databinding frameworks? So far, I've been somewhat skeptical of those--I worry they make too many assumptions and take away too much fine-grained control.
- brandoncapecci 12y agoThe amount of people I know who use functional frameworks (say Underscore) to build things but don't really know much about functional programming is astonishing. To be fair, a lot of frameworks that espouse "functional programming" do so just because it's popular and really push imperative concepts instead so it's easy to be confused on the "right way".
- jarrett 12y agoI love Underscore (and Haskell), but I wouldn't consider Underscore an FRP framework at all. It's functional, yes, in the sense that it provides some of the most common FP operations like map, filter, etc, using lambdas. But I don't see the reactive part. Maybe there's some kind of reactive feature tucked away in Underscore's rather large feature set, but I haven't seen it, and it's certainly not core to the library.
- seanmcdirmid 12y agoDatabinding is not FRP, but you can do a lot of FRP things with it. If you are into WPF, check out Bling: http://bling.codeplex.com/ http://bling.codeplex.com/ We are able to subvert WPF databinding mechanisms to allow bindings to expressions as well as functions. The act of binding itself is still very imperative (and so, not very FRP-ish), but beyond that the programming styles are quite similar.
- steveklabnik 12y agoI'm speaking about ones that are explicitly FRP, like Bacon. Data binding stuff is pretty close as well.
- mattgreenrocks 12y agoI think FRP is a good idea; but it seems to expose a failing of many languages: the lack of metaprogrammability. In particular, most (non-Lisp) languages don't let you mess with control flow much. The result is that when writing FRP code, users have to manage two control flows: the 'logical' control flow, which is expressed via whatever FRP library they're using, and the actual control flow, which is the one provided by the language they're in. Languages would need good support for source-to-source transformation, or, alternatively, allow the compiler IR to be manipulated by libraries. From the little I've played with Haskell, it appears the monadic binding operator (>>=) lets you do this, and the user writes code in an idiomatic, imperative-like manner. It is extremely impressive that this capability can be used to arbitrarily extend the language, while being a very small concept. Edit: not sure if I had my terms right on the operator.
- steveklabnik 12y agoYup! I would agree with this too. I've actually written an FRP library in Ruby[1] and it's not really _useful_ yet because of these kinds of issues. I was thinking about how I'd use it to build a web framework, for example, and I'm not sure it's a significant improvement. Regarding >>=: yes, it's the 'bind' operator, and yes, it is really impressive. This is why monads are hard: they're so abstract that they're good for _many_ things. It's also why they're so great. 1: https://github.com/steveklabnik/frappuccino https://github.com/steveklabnik/frappuccino
- mattgreenrocks 12y agoFRP strikes me as much, much closer to how Things Should Be(tm), but it still feels off somehow. Perhaps it's just too low-level. It should really part of a language's runtime, rather than exposed to the user. Right now, most FRP implementations kind of take over your system: you're always sweating whether this is a special reactive type vs your domain type. Even C#'s async/await (not quite the same thing as FRP) seems to have a similar effect, where the async function keyword propagates through your codebase quickly (caller/callee have to agree on this I believe). FRP still feels like it's in the early stages, so I'm confident someone will find a better way to apply it. Right now it seems more palatable to non-bleeding-edge devs if you tailor it for specific use cases, rather than the whole thing at once. It may be the concept is too big to sell right now.
- marcosdumay 12y agoI wonder if FRP wasn't a better alternative than STM for inter-thread communication. I'm looking at a very similar problem (in form, not area), and literaly wondering that...
- seanmcdirmid 12y agoThere are solutions that use elements of both, if you are into research, check out: http://research.microsoft.com/pubs/211297/managedtime.pdf http://research.microsoft.com/pubs/211297/managedtime.pdf
- jcurbo 12y agoSeems like FRP is catching on in other languages (as steveklabnik's sibling comment mentions, Javascript, and in C# and Objective C) but in Haskell it still seems to be a wash; there are a bunch of competing frameworks and, as far as I can tell, no clear leader. I used reactive-banana to do a school project last year, and it was ok but not on the level of Rx or ReactiveCocoa as far as I can tell. There are a half-dozen or so other frameworks, and some of them are implemented differently from others as the research moves in different directions (different ways of representing events/signals, using arrows, etc). Of course, for this specific use case (GUIs) there are similar issues in terms of implementations of GUI toolkits in Haskell (GTK? wx? some other half baked ones? and so on) But back to your other point, sure you can write imperatively in Haskell and use IO and so on, but to really take advantage of the strengths of Haskell you need to write declaratively (i.e. functionally) and take advantage of the ways that helps you write things like GUIs (which are naturally declarative).
- efnx 12y agoOr you can use do notation inside the state monad and keep everything pure. Then you get the best of both worlds.
- dustingetz 12y agoI dont think you need FRP to do that. In ReactJS, view code is pure, dom event callbacks just return new states[0], and all IO (ajax data access), async pipelines etc stay at the very top of your application at the root of the view hierarchy. Business logic is just functions of data values and/or appstate values. Which is exactly how I imagine the idiomatic haskell solution would look. [0] dom callbacks actually swap! the nextState value so there are effects down there at the bottom of the view hierarchy, but that's react's fault for not letting you return the next state. e.g. <input value={this.state.a.b.c} onChange={_.partial(mori.assoc_in, this.state, ['a', 'b', 'c'])} />
- seanmcdirmid 12y agoInteresting. ReactJS sounds like an immediate-mode UI that avoids states and reconstructs the UI by re-rendering. This is as opposed to a retained-mode UI that is based on a mutable scene graph.
- mattgreenrocks 12y agoExactly: https://twitter.com/ibdknox/status/413363120862535680 https://twitter.com/ibdknox/status/413363120862535680 It's amazing that we're back to immediate mode!
- seanmcdirmid 12y agoThat makes sense (can't read Chris's comment right now because I'm behind the GFW). Immediate mode is quite workable and can even be efficient with the appropriate amount of memoization. State can even be injected in a way that is very FRP like (re-render over values that changed). Seems like I have more related work to talk about :)