3 ms·
Shameless plug - I'm trying to improve upon Elm and React's programming model with my Concur UI framework. Its programming model is a bit unusual, it uses Monad
by haskman 8y ago
Shameless plug - I'm trying to improve upon Elm and React's programming model with my Concur UI framework. Its programming model is a bit unusual, it uses Monads to sequence widgets in time, but it is designed to be extremely simple to use, and you don't need to actually understand Monads to use it. An advantage is that it's not artificially restricted like Elm, and allows you to use advanced Functional Programming tricks when you can and want to.
It is available for [Haskell](https://github.com/ajnsit/concur https://github.com/ajnsit/concur), [Purescript](https://github.com/ajnsit/purescript-concur https://github.com/ajnsit/purescript-concur), and [Javascript](https://github.com/ajnsit/concur-js https://github.com/ajnsit/concur-js) (so no need to learn a new language), and also allows using external React components. The Javascript version uses Async Generators as a substitute for Monads.
With Concur, you can implement the entirety of Elm architecture with a few lines of idiomatic code.
Purescript or Haskell -
elm render update = go
where go st = do
action <- render st
go (update st action)
Or in JS -
function elm(render, update){
var go = async function*(st) {
action = yield* render(st);
yield* go(update(st, action));
};
return go;
}
- the_gipsy 8y agoAren't those few lines missing all of async/IO/runtime stuff? Is all that supposed to happen inside `render`?
- haskman 8y agoEdit: I changed my response after I took the time to understand what you meant. Concur has a very uniform programming model where you do everything by composing widgets. `elm` is a widget. `render` also is a widget. As such both can perform arbitrary async effects, and they take place inside event handlers, or inside lifecycle methods like componentWillMount. Concur takes care of managing that for you. So to log all actions to the console, you can add a logging call to `elm`. elm render update = go where go st = do action <- render st liftEffect (log ("Action - " <> show action)) go (update st action) Meanwhile, the render function itself can be a widget which performs side effects - view = do evt <- button [onClick] [text "Click me"] liftEffect (log "Button was clicked") return evt There are lots of examples of effects in the Concur repo - Take a look at some running examples here - https://github.com/ajnsit/purescript-concur/blob/master/examples https://github.com/ajnsit/purescript-concur/blob/master/exam... And running demo - https://ajnsit.github.io/purescript-concur/ https://ajnsit.github.io/purescript-concur/
- the_gipsy 8y agoThanks for the explanation! I think Elm isolates its “views” much more, but concur might be easier (less boilerplate). I will definitely give it a try now, sometime.
- hardwaresofton 8y agoI've always thought that Elm was like Purescript in the way that it was just another way to bring the good parts of Haskell (a good type system) into JS. I didn't consider elm's architecture as the main value proposition -- if you squint it looks just like every other data management model for component-based approaches these days -- flux, redux, etc all work in a similar way, +/- immutability. Hopefully people aren't out there thinking that Elm has done something to magically make it much harder to write runtime errors -- they added a powerful ergonomic-where-possible type system. If developers out there are still thinking types are "bad for JS" or that using types in code is weird/unnecessary, they might be suffering from Blub[0], and need to go out and see what other languages are doing maybe widen their perspectives. Not every language with a good type system looks like Java/Dart/Typescript/etc (some people can even argue that Java doesn't have a good type system) and I often meet engineers who think adding/checking types basically means making javascript into java. [0]: http://wiki.c2.com/?BlubParadox http://wiki.c2.com/?BlubParadox
- haskman 8y agoFlux/Redux were inspired by The Elm Architecture. I don't know if there was something similar before Elm popularised this style of building user interfaces. Concur was first written in Haskell, so it's got the Functional Programming part down :) The other interesting part was TEA, which is hard to simplify further, but I think Concur's model manages to do that while simultaneously being more powerful. Edit: I don't know what gave you the impression that I don't like types. I love types! I wish JS had more of them. I write Haskell/Purescript (and Javascript) in my day job.
- hardwaresofton 8y ago> Flux/Redux were inspired by The Elm Architecture. I don't know if there was something similar before Elm popularised this style of building user interfaces. Didn't know that, weird how it's come full circle in a way, I don't think people would consider Elm as approachable as they do now if React, Flux and resultingly redux hadn't gotten so popular. There was also a bit of a hype train behind FRP for a while but that seems to have petered out a bit. To be fair I'm not an Elm expert but try to keep up with it, I have yet to write something big in it, but I absolutely believe the hype because the hype isn't hype, those of us that are writing or at least peeked at the Haskell/ML world have been living in this world up until now. > Edit: I don't know what gave you the impression that I don't like types. I love types! I wish JS had more of them. I write Haskell/Purescript (and Javascript) in my day job. Sorry I didn't mean to imply that you don't, I will go back and edit my comment -- I meant I still run into that sentiment, most recently at a meetup last month. It's not like I don't understand it, you can move faster without type checking but a lot of times that just means letting code with silly bugs through that you're going to find @ runtime.