Hacker News new | past | comments | ask | show | jobs | submit login
Making Elm faster and friendlier in 0.16 (elm-lang.org)
243 points by jwmerrill on Nov 19, 2015 | hide | past | favorite | 90 comments

I find the Elm language quite fun and I think it has potential.

However, I'm absolutely not convinced about "the Elm architecture" for anything but the simplest UIs. Is pure functional reactive programming suitable for ambitious UIs ? I do not think so.

React has its own set of flaws but at least I believe it nailed the state problem: Encourage the minimization of local state but still make it easy to have some when necessary. I like functional programming a lot but I think this is a case where good old object oriented encapsulation provides a more pragmatic solution.

There are all sorts of transient states that a parent's component shouldn't have to care about (Whether I currently have focus, a transient list of changes not yet committed that should be thrown away should I navigate away, is the calendar drop-down opened?, etc, etc) Elm makes it hard to have truly rich and reusable components for that reason as all that transient state must leak to the parent components.

But that's still doable at least, if cumbersome; some other things simply appear impossible, like coding a ReactTransitionGroup equivalent. This React component encapsulates the concept of a changing-over-time list of children and animate in/out the children that changed across two redraws. It needs to know about the previous list of children to diff it with the new. It needs to manipulate the actual Virtual nodes passed to it so that it temporarily leaves the exiting nodes till their animation finished, etc. This thing has tons of state and it needs it to do its job; and it's fine. How would you do this in Elm without leaking the abstraction at every call site ? (I'm looking for a pragmatic, easy-to reuse by everybody solution, not some convoluted sliding Signal of component lists ;-) )

I'm wondering whether performance tweaks should be the focus right now; Elm already had good performances. The issue is adoption, and if it's too convoluted to write (non trivial) reusable components, I don't see how it can succeed. Right now I would never start a complex project with it in fear of getting stuck with a medium-complexity task because the architecture didn't foresee my problem.

Maybe the architecture provide some escape hatches I didn't see, and I would love to be proven wrong.

Local component state is the new two-way data binding.

Three years ago, two-way data binding was the gold standard for niceness. Then React came out, and there was buzz around unidirectional data flow, and a lot of (understandable!) skepticism came with it.

If you listen to people who have spent a lot of time with two-way data binding and unidirectional data flow, what you hear are a lot of unidirectional data flow converts and not a lot of people saying "yeah it wasn't awesome so I went back to two-way data binding."

We're watching the same thing play out with local component state versus a single state atom architectures like The Elm Architecture, Redux, etc. As with the React transition, there is understandable skepticism around new things claiming to be nice, but the writing is on the wall.

If you listen to people who have spent a lot of time with both systems, what you hear are a lot of single state atom converts and not a lot of people saying "yeah it wasn't awesome so I went back to local component state."

@rtfeldman -- I think your response is a bit disingenuous since only yesterday you wrote, in response to a question about cursor state, this:

"I wouldn't maintain cursor state in the model; I'd just implement the port like this: http://stackoverflow.com/a/14508837/2334666

In other words, you never use the value attribute on the input; rather, you give it a unique key and don't touch it directly. Whenever you want to change its value, just send the desired new value to that port and let the JS snippet do the "stash cursor position, set the new value, restore cursor position" bit.

If you need to do this for multiple elements, send a DOM query string to the port and call document.querySelectorAll (or the like) with it to apply the logic to the correct element."

(See https://groups.google.com/forum/#!topic/elm-discuss/I2JleY8b...)

Clearly, you don't even believe that all component local state belongs in the atom. And kicking the issue to JS-land is just hiding the problem.

Almost everything should be unidirectional, but @boubiyeah has a valid point. Not everything belongs in a single state atom. (I say this having written a 4000 LOC Elm app, which I'm porting Clojurescript/Re-frame due to precisely this issue.) Even Haskell uses mutable references for this stuff.

That's not at all disingenuous; the two are completely unrelated. :)

The DOM uses local state extensively, and sometimes you need to interact directly with its API. When you do, you can either do more work to translate it into your preferred architecture, or not.

In this case I didn't think the extra work required to wrap the DOM API for cursor position would be worth the trouble.

That's certainly not an endorsement of the DOM's architecture. ;)

> "The DOM uses local state extensively, and sometimes you need to interact directly with its API. When you do, you can either do more work to translate it into your preferred architecture, or not."

> "Local component state is the new two-way data binding. . . If you listen to people who have spent a lot of time with both systems, what you hear are a lot of single state atom converts and not a lot of people saying "yeah it wasn't awesome so I went back to local component state."

> "I wouldn't maintain cursor state in the model . . . Whenever you want to change its value, just send the desired new value to that port and let the JS snippet do the "stash cursor position, set the new value, restore cursor position" bit."

The question we were addressing is where your state should live. @boubiyeah questioned the wisdom of storing all component state (e.g., the current position of a cursor) in a global atom. You responded that "[l]ocal component state is new two-way data binding." Yet yesterday you advised that component local state should live outside of the global atom.

Maybe it wasn't disingenous, as perhaps you've simply changed your mind. But then you should make clear that your opinion today is different from what you advised yesterday, as it bears on the credibility of your current advice.

Hm...my response was the exact opposite of that. Maybe I need to rephrase?

In bullet points:

1. Yesterday someone presented a case where they needed to interact with a DOM API that used local state.

2. I didn't think it would be worth the trouble to wrap that API.

3. That is not an endorsement of local component state.

Hopefully that clears things up. :)

Don't feed the troll. While @ablesearcher's obviously part of the Elm community, he's using a throwaway account to vomit angry rubish on HN.

When did evidence-backed criticism become synonymous with trolling? Also, which statement exactly was angry? (Let alone rubbish? Or, gasp, vomit?)

It seems you want all Elm news to be positive Elm news. So does the language's author. In fact, when addressing the announcement re: Hacker news, he wrote this:

"Just an FYI, if you go to a HN post via direct link and vote on it, those votes either do not count or are used as demerits because it indicates that people are trying to artificially boost things. I guess getting a kickstarter to the top of HN can be worth a lot of money, so they try to protect against voting rings."

(See https://groups.google.com/forum/#!topic/elm-dev/NQxML4HA4X8 )

Civility is important. But so is the honest, unfettered exchange of ideas.

Well, for starters, use your real name, like the rest of us, not a throwaway account.

I guess if your issues were legitimate, we'd see a post on the mailing list, not an open attack on Richard's credibility.

For the record, this is evidence-backed criticism:


Yours is just trolling.

Let's proceed in reverse order:

1. You don't get to define evidence-backed criticism to be only the criticism that you appreciate.

2. I didn't "attack" Richard. I pointed out an inconsistency with other recent statements that he has made, that bear on the credibility of his current advice.

3. I'm not sure how my identity is relevant to my ideas. But the reason I don't post under my own name has to do with requirements of my job. (I'm not a programmer by trade.) I can't have social media accounts. In any event, this isn't a throwaway account. These are, in fact, my first posts to HN.

Not everyone disagreeing is a troll.

So basically you think it's ok to use local state, but only for DOM related stuff?

Nope, just that the effort required to wrap something in a nicer architecture sometimes outweighs the benefits you'd get from the upgrade. This was one of those cases.

Maybe the answer is for elm-html to put a cursor-state attribute on textual input elements, and have event handlers for selection change? Then you can have the cursor state in your atom if you need it without ports....

That might solve the cursor issue, but it's a bigger issue than cursor state.

The real issue is that Elm doesn't treat its programmers like grown-ups. That sounds harsh, so let me explain . . .

I've drank enough of the Haskell Kool-Aid to realize that, despite the surface discourse, Haskell is not about religious devotion to purity and lazy-evaluation. It's about managing side-effects, and being honest about them in your type signatures. Yes, Haskell allows functional purity but its real genius lies in how well it helps you manage state. (I did an imperative Algorithms course completely in Haskell, and the language really shines. Mutable unboxed arrays, mutable atomic references . . . it's all there when you really need it.)

Unfortunately, the folks driving Elm development take a paternalistic tack. (If someone seeks to argue this point, it's not hard to come up with many, many examples from the Elm mailing lists.)

Here's a few examples:

- Elm shouldn't have type-classes because, allegedly, they are too hard for JS-folks to understand. (https://groups.google.com/forum/#!searchin/elm-discuss/type$...)

- Elm doesn't publish how you are supposed to write native modules (you must discern it from the code and it's subject to change without notice), because Elm's author thinks you can't be trusted to use FFI wisely. (https://groups.google.com/forum/#!searchin/elm-discuss/nativ... and the can was kicked here: https://groups.google.com/forum/#!searchin/elm-dev/native/el...) And, no, Elm's ports are not the equivalent of FFI.

- In the most recent release, operators were removed because synonyms for map (<~) and apply (~) are allegedly to hard understand.

- Appartently, you shouldn't even mention Haskell as a resource for learning Elm. (https://groups.google.com/forum/#!topic/elm-discuss/OlzLOPix...)

I think it's healthy for programming languages to have a point of view; that is, languages should lead you in a direction. (Clojure does a great job at this.) Yet, ultimately, a language shouldn't censor its programmers.

Upshot: Component local state should be an option in Elm when you really need it.

Evan has described a lot of the thinking behind his decisions in this talk: https://www.youtube.com/watch?v=oYk8CKH7OhE

The <~ for Signal.map is a good example for a "clever" thing which makes languages hard to read for newbies. It looks like it's part of the syntax and not a function. It's not hard to understand, but it's another thing to learn. I am very happy that things are removed from Elm (or not added in the first place, like type classes) because design is not finished when there is nothing more to add but when there is nothing more to remove.

I've seen Evan's talk. Evan confuses the presentation of features with the value of those features. (I suppose one could solve the difficulties people have in learning Mathematics by throwing out everything after Algebra I; another solution, however, might be to do a better job teaching the more difficult stuff.)

Just because you shouldn't expose new programmers to advanced concepts on the first day doesn't mean they shouldn't be a part of the language. Similarly, the fact (<~) might confuse someone new to Elm isn't a reason for removing it from the language.

I'm sympathetic to the concern that some code is too "clever" or dense; but Elm swings the pendulum too far.

(Btw, type-classes are not incidental complexity:

https://www.youtube.com/watch?v=6COvD8oynmI https://www.youtube.com/watch?v=hIZxTQP1ifo )

It seems backwards to me to optimize a language for newbies.

This is what I expected would already be setup - it'd be a pain to deal with cross-browser stuff when implementing it, but it'd be a dream for app developers (me).

Actually, you do see a lot of questions and problems with the single state atom. In fact, I'd argue it's inherently a side step towards a future that has the best of both worlds: encapsulated state within components, but backed by some global state store invisibly.

This is exactly what Relay is by the way. You component asks for state, and gets it from a server. The fact that it comes through props is actually just a downgrade because it means you must now treat it as some special thing, and not variables.

In the ideal world, we can write simple components that fetch state from wherever (remote, local, global). They store that state into themselves, and it "just works". They can write back that state just like how they write variables. And all of this "local" state would really be backed into a global state store invisibly.

Local state - Pros: easy to reason about, easy to use. Cons: trapped in one place, inflexible.

Global state - Pros: can be backed in various ways, easier to share. Cons: Hard to use, harder to reason about.

Local state backed to global store - Has all the pros and none of the cons. Unfortunately doesn't exist yet today.

Hi there,

I do not quite agree with this. Though I acknowledge your sentiments :-)

1. Global state is easier to reason about. If you have a single state store expressed as a single object you only have to read one file to understand the complete state of your application. If you let local state express the state and the global state is invisible you have to look into all these local state files and compose the complete state in your head

2. When you define it as local state you risk conflicting with some state set in a different component

3. You still have to change state. If you define your state in your components you will also have to include all the state changing logic inside the component. Your components will become very hard to reason about. And what if two components uses the same state and both of them needs to update the state? You will need to put the same logic into two different components

4. You could say Relay fixes this, but Relay just handles one thing and that is state related to the server. We build applications that does a lot more than talking to the server. Changing the state of your application is a huge problem space and though Relay is cool technology I can not imagine anyone expressing and changing all their state using Relay. So you need some other concept(s) to change all the other state and multiple concepts for doing the same thing is harder to reason about

Personally I think local state is a bad idea and currently I also think Relay is too limited. When I jump into an application I need to reason about what state it handles. With a global state store I can do that. Then I need to know how that state can be changed. Ideally that should be one concept, but we usually have lots of concepts for changing state. Then I want to see how the UI is expressed. Components are great for that, except when they are filled up with state definitions and state changing logic.

So from my perspective I am also trying to contribute with a solution :-) www.christianalfoni.com/cerebral

Good points. A response:

1. Global state is easier to see on a high level, but harder to reason about. Local state is inherently easier to reason about: it's right there. Global state requires me now looking at actions/signals, global state structure, and then my component, and resolving the three.

2. They should definitely be synchronized, this problem is only specific to local state implementations today. If they aren't synchronized, thats simply at the lack of the system you're using. I'm not familiar with Om Next, but I'd guess it handles this for you (as could any system properly organized).

3. Not true. You could have state changing functions imported and used by multiple components. This is also easier to understand, in my opinion. I can see where the state is located, and still keep my shared state changing functions somewhere.

I do think local state is skewed negatively now because it's very poorly done. React, angular, all systems today make local state a total pain, opaque, and hard to work with. Om Next seems to be a step forward (I'm working on something somewhat related for JS that should make it better as well).

This is really interesting, we have very different perspectives on how to consume how an application works. Not saying you are wrong at all, just have different perspective :)

1. When I say "global state" I mean the actual state, actions and signals are state changers, not state. A global state store looks like this:

{ admin: { users: [], showConfig: false }, home: { isLoadingNotifications: false, notifications: [] } }

This is one file. If you use local state this example would be split into maybe 3 different files. I think we both agree it has to do with how many files you need to look into. And the amount of composition you need to do in your head.

2. It would be interesting to see Om Next in JavaScript syntax, too much brainpower going into trying to read Clojure :) Not because it is bad, just have not learned it

3. That is true, but now it is conceptually no different than signals/actions and for that very reason. You should look into a different file to read the state change. I think it is a good thing. State changes are often very complex, surprisingly complex. They should not be inside a component. I think a component should only be about rendering UI. State changes should be expressed by a different layer.

So what I think is interesting here is that we seem to look at the app from two completely opposite sides. I do not care about the components to understand my app, because they just express its output, the UI. My app is really the state defined and the way it changes that state. What I do care about though is having dumb components is that makes me able to do universal apps, just move my app to a new UI output like react-native etc.

It will be really interesting to see how Om Next affects the JavaScript community. We are good at getting ideas from other languages and practices, where Elm is a good example :)

Again, not stating that you are wrong about anything. It is nice to go into a component and understand how that component works. Its just in my experience really bad to use a "view" as a container for state and business logic. That said it is really important to be open minded and I hope to see us grab ideas from Om Next. Actually trying to inspire creator of Baobab to bring in some new ideas :-)

We use both; local component state as long as nobody else (might) be interested (this usually the case for generic components that are not application specific, such as page controls, checkboxes etc). But as soon as state starts to creep upward in the component tree, we move it directly to global state and store it in observable data structures (using mobservable) so that any component interested can use the data in whatever way it was delivered (through props, global state, closures, etc) and (un)subscribe automatically.

Have you tried Freezer.js?


It is a global store that can be modified inside of the components safely, as if it was component's local state.

A change anywhere in the store will trigger an update event at the top of the store, notifying the rest of the app. So if you use a part of the freezer store as local state for your component, you'll get both requirements:

* Any change to the local state will rerender your component - ease of use. * Your component's local state won't be hidden anymore. You will be able to access it from outside the component.

Take a look at Netflix's Falcor (full disclosure: I wrote lots of it).

Don't know, I never liked two-way bindings :) <MuseumTech>Adobe Flex added those at some point but it was a complete downgrade from the simpler one way bindings + events.</MuseumTech>

A central state atom has pros (debug tooling and the fabled undo for free being the main ones?) and cons. The cons affects me more than the pros. Clojure's Om and React+redux maintain a central atom but still allow for local state in a pinch.

I appreciate your comment but I wish it was a bit more constructive; Why do you think a central state atom is so much better ? How can one write ready-to-use smart components with central state ? (e.g ReactTransitionGroup)

Here's a long-form answer to both questions. :)


Fine article... But all that it tells me from my experience is that it's a good thing to put 80-90% of the app state in a central atom :p A good practice or rule of thumb is just that, it shouldn't always be the only way to do things.

Flexibility is a fine rule of thumb, but opening the door in those 10% of cases costs you things like time travel.

Quite a price tag! :)

I went back to component state.

I have been studying this, Elm explicitly forbids "signals of signals". This basically bans dynamic mutation of the dataflow graph and makes dynamic Gui's very difficult. The solution is not to enable signals of signals, because they are a source of problems. The solution would be to hoist all the functions up one level and operate on a dataflow graph comprised of transformations of signal transforms. This will kill many of the nice properties of Elm (hot code replacement), but the cost of the current system is that its unusable for application context switches and dynamic GUIs. In the literature the high level style of FRP is called AFRP (arrowized FRP).

I am currently prototyping AFRP ideas in Typescript and RxJS, although its very early days and basically not usable ATM. https://github.com/tomlarkworthy/animaxe (a better typed version is in a branch and not compiling ATM)

It looks like you can always avoid needing signals of signals by declaring one signal for each type, not a signal for each instance.

All instances of the same message type can share a signal, as long as the messages contain a unique key to distinguish between objects, and the code that lives downstream filters events by key.

It's much like a database-backed app where you don't dynamically create tables while your app is running. Instead, instances are stored within a table and identified by their keys.

No because you must might want a whole subgraph of dataflow associated with each instance. You are right you can perhaps do it with collection primitives as signals. Creating tables is appropriate for multi tenancy apps. Or apps that let you build apps, or analogously, a drawing program for graphics.

So, an app builder will need to simulate signals in a purely functional way, rather than using the top-level, native signals. But if you want to write a debugger for the child apps, you need something like an interpreter anyway.

At the top level you might just have a single native signal for all events delivered to any child app.

But I agree that the ability to start and stop reactive sub-programs would be a useful thing.

What do you mean by "dynamic GUI"? As opposed to what other kind of GUI?

A GUI with n buttons and a button to add and remove additional buttons

Yes ... but with a more natural implemention. That style won't scale up to real dynamic programs though without significant routing infrastructure outside of Elm's typical constructs.

Naturalness as a criterion for evaluating languages is not that compelling to me. I think a honest word for what people usually mean when they say "natural" in this context is the word "familiar". I know plenty of programmers who think that OOP is just more "natural" than FP.

What I really would like to see is a counter example. Some GUI that just can not be done in Elm.

> What I really would like to see is a counter example. Some GUI that just can not be done in Elm.

I'm on the Elm/FRP fence myself but your comment here reeks of turing tarpit:

"Beware of the Turing tar-pit in which everything is possible but nothing of interest is easy."

Without going on too long a tangent, this hasn't been our experience in practice at NoRedInk. We've built some absurdly complex UIs involving those same design needs, and what you're describing just has not been a problem.

I'd suggest giving it a try. It's really nice. :)

> There are all sorts of transient states that a parent's component shouldn't have to care about.

The problem with this way of thinking is that there are invariably things that you initially believe will be of no concern to the parent that later become concerns of the parent. It's tempting at that point to graft on some event system so the parent can watch the things that it now cares about, and then maybe you add some hooks to allow the parent to preempt or change certain behaviors. This evolution requires careful thinking every time, and it's easy to make mistakes.

The great thing about the elm architecture is that from the very beginning, it gives the parent all the hooks it will ever need to observe and modify the behavior of children. In the beginning, when the parent doesn't care, it just passes the actions up and passes the model back down without having to look at them. That might feel a little bit boilerplate-y at the beginning when you don't need it, but it's the same everywhere, so it isn't difficult at all. And once you've done this, evolution of the components requires much less thinking about architecture, and leaves much less room for mistakes.

If you make all events public, you end up sending all scroll events and mouse move events to the app's top-level signal just because some component needs them. The larger your app is, the more likely it is that some component somewhere will need an event sooner or later.

Traditional UI frameworks try to avoid sending events unnecessarily for performance reasons; they're designed so that each component can declare which events it's listening to and can start and stop listening as needed.

Perhaps Elm can make this work, so that unwanted events get filtered out so quickly that it's not a concern. Also, these days everything gets animated anyway based on things like scroll events, so apps are perhaps a bit more like video games that run at 60 frames/second regardless of what's going on, at least while they're in the foreground. And the browsers themselves perform a lot better.

But it shouldn't be hard to see why people who have experience building UI frameworks might be concerned about unnecessary event traffic, particularly on mobile where battery life is an issue.

I think that's a fair point. To be honest, I'm more concerned about the real limitations of the paradigm (the nice-to-have features I will have to pass because the architecture is a bit too closed)

I think there simply needs to be more exploration in the area. I only know of one person who tried something truly different than the Elm Architecture who wrote about it on the mailing list. Anyone interested and with time to spend should just try different things, be critical of their attempt's ease of use and ease of abuse and see what works.

I think eventually there might be a performance problem with scaling, and yes each components seems to have a bit of boilerplate. But overall the pattern is very reusable and predictable, so if it really becomes the standard (instead of the experiment that it is now!) there could be compiler support for less boilerplate/ better performance.

For now I haven't seen enough people with actual experience using this architecture to really buy any complaints. I've seen more unintuitive things come around in Elm that seem weird (perhaps even wrong) at first, but by really trying it out, I've found that more of those things work really well!

Do you happen to remember what was the idea of that approach alternative to Elm Architecture?

You can have component local state in the Elm architecture. If you work through the Elm architecture tutorial (https://github.com/evancz/elm-architecture-tutorial/), section 6 describes how to do it. You can also have both local and global state if you want. Just follow the tutorial and in your "model" type add a record called "global". Than let each component take and return both the local and the global model. I personally use global actions instead of a global model. In this approach each update function for a component returns a new model and a global action. Each component has a "updateGlobal" function which is than called with all the actions returned by the update functions of all the components. This way, components can talk to each other, but may keep completely different models. Here is the relevant code in my main elm file: https://gist.github.com/brodo/6495e486648d235e10a5

This allows you to react differently to actions in each component if you want. You can check out the whole project here: https://github.com/brodo/MushroomCup/tree/master/elm

Your solution redefines the word "local" to mean "global." Yes, you can store a component's intrinsically local state as field in your global model and then use a specialized update function that is reached by a switch from your global update function. The question we are addressing is: Is that a good idea?

You realize that each component can not see the other components local state in both solutions i suggested?

Fwiw React-motion solves TransitionGroup in a purely functional manner. https://github.com/chenglou/react-motion

I have been contemplating the same issue. Unfortunately I haven't yet had enough of a chance to write a large complex application to verify whether or not the Elm Architecture works in practice. In particular the potential for actions and effects of subcomponents to pollute the code of parent components concerns me. If you have some further insight I would love to see a blog post comparing React and Elm that demonstrates where the issues are. Also, the Elm community could potentially make suggestions or take those issues into account for the future.

Regarding global state and React, this looks relevant: https://www.youtube.com/watch?v=Uu4Yz2HmCgE&t=11m37s

It seems to work for NoRedInk and CircuitHub...

It is also possible to write the most complex app ever using just vanilla Javascript/JQuery too, but it's not viable or fun to maintain.

The elm language brings a lot of value compared to the very unsafe javascript; I'm only questioning the validity (or immaturity) of the component architecture.

My thoughts on this based on experiences using Elm at scale at NoRedInk: https://twitter.com/rtfeldman/status/667419654370033664

I'm just finishing up a first-year course at McMaster University where we learned basic CS concepts (divide and conquer, state machines, recursion, algebraic data types, FRP, etc) using ELM. It's the first time I've ever put an honest effort into learning a pure functional language, and although it was initially frustrating to a self-taught programmer with a background in several procedural languages and SQL, it's growing on me, and I'm probably going to look for a side project (maybe a small game or a simple CPU simulator) to build with ELM when the course is over.

I only wish the "Improved error messages" and "Catching more bugs" features had been introduced about three months ago, probably would have saved me hours!

Some of these errors remind me of Rust and the attempts in that community to give every error an exhaustive description [1].

This looks fantastic, and shows a true commitment to reducing friction with the language - a goal which often goes too long without attention.

[1]: https://github.com/rust-lang/rust/issues/24407

Yup, I would strongly agree. Diagnostics are one of those things that's easy to let slip by the wayside, but we've seen a huge payoff for users with all the time we've invested in ours. Glad to see other languages like Elm help raise the bar here too.

Elm is a beautiful expression of a language. Alone, it is a work of art. Put to use, it lets you build works of art. One of the best contributions to modern languages.

Long anticipated, and now finally here :) I <3 the type diffs, exhaustiveness checks and TCO. Not completely sure about the removed syntax, but it's not like I used it a lot, so I guess simpler is better.

Very nice. I love the "beginner hints" idea, and explicit enumeration of which cases are missing in incomplete pattern matches. Overall, the "compilers as assistants" idea seems great.

Finally TCO! Actually in my UI-heavy Elm programs it isn't that often that I have to write functions with large recursion depth. But it is really comforting to know that the compiler is analyzing my code and making it more efficient. :)

Has anyone tried Reflex? Really interesting concept in Haskell + GHCJS https://github.com/ryantrinkle/try-reflex

I liked Elm but I felt the language was a bit limited coming from Haskell, ex no type classes so you have List.map, Signal.map, Set.map, etc

Overall Elm is great in terms of tooling, setup, error messages, performance, js interop though

Reflex is great (and its author is a genius) but it's not really useful yet for non-desktop apps. Because Reflex + GHCJS is impossibly slow on mobile.

As an experiment, try using chrome (iOS) or android to load this:


or this:


They're both reflex apps.

GHCJS is bees-knees. But unfortunately, minimizing-code-size/mobile-performance has not been a priority. (It's understandable, as Luite can't do everything himself.) (Aside: the best solution I've seen -- in terms of generated code size -- in GHCJS-land right now is: https://hackage.haskell.org/package/react-flux. Anecdotal, though. YMMV.)

I can't wait for GHCJS to be ready for prime time. I wish all these alt-JS-haskellish language authors (of Purescript, Elm, Roy, etc.) would just work on making GHCJS better.

It's a bummer that Clojure and Scala are much newer than Haskell and yet they both have a mature, production-ready JS compiler. The statically typed ML-family is too small for multiple JS compilers. The entire community needs to pick one and let the others die. Otherwise, we end up with several half-baked solutions and not a single industrial-strength one.

> I wish all these alt-JS-haskellish language authors (of PureScript, Elm, Roy, etc.) would just work on making GHCJS better.

All three of those have very different goals and trade-offs from GHCJS.

I agree that it would be nice to share more work/knowledge though. One of the nice things about AltJS is that several languages can coexist in the same codebase.

> "All three of those have very different goals and trade-offs from GHCJS."

And therein lies the problem. In my view, the most important goal is to have at least one really good AltJS-Haskellish language with a fully-featured ecosystem of libraries. (I'm fine if that language is PureScript, btw. PureScript is fantastic.) The problem -- which Clojure and Scala programmers seem to have sorted -- is that our community is too small to support several Haskellish-AltJS compilers. Do we really want several perpetually nascent solutions?

> "One of the nice things about AltJS is that several languages can coexist in the same codebase."

Theoretically, you're right. But how many production code bases are there in AltJS-Haskell (vs. say, Clojurescript)?

Normally very smart people have an huge ego and hate politics. It's always a pity to see so much potential wasted.

Can something like JSX be used with this? It looks like a cool language, but I was never able to get behind HTML "DSLs". Their only advantage is ease of implementation and that you get to write in your current language, at the expense of write/read verbosity and comprehensibility.

Even Jade/HAML/Slim I'm ok with, since they're a terse iteration on HTML rather than a nested monstrosity of code blocks. But I prefer JSX or Handlebars.

I'm yet to see strong objective reasoning either for or against JSX, it seems to really polarise people. From an Elm perspective, I feel that the HTML API is well designed and doesn't get in the way, so I'm not entirely fussed.

I wish the clojure compiler also had the explicit goal of making things easier like this...

There is hopefully some movement in that direction after my talk at the conj: https://www.youtube.com/watch?v=kt4haSH2xcs. I'm continuously inspired by Evan's approach and his dedication to the user experience, and I hope to be able to bring some of that to Clojure.

Elm is such a pleasure to learn. I really need to sit down and write something non-trivial with it one of these days.

I'm trying to decide between Elm and React/Reflux for the js part of a side project. I'm concerned about learning curve and awkwardness of adoption if the project ever turns into something someone else is coding on. I know they are very different technologies, but I think others must be choosing between them. Any thoughts from those who have tried both?

I personally like React + Immutable.js (for the store) + Redux (https://github.com/rackt/redux) which is more similar to Om and apparently Elm. It's actually the first Fluxlike implementation I willingly use.

I'm using the same stack (minus immutable.js, but I'm thinking on it), combined with redux-simple-router. Apart from the usual problems associated with Javascript, it works pretty well, and I feel it's easy to understand what is going on.

On the other hand, there are some pitfalls. Since you may need to trigger actions based on some transient state (eg, fetching data from the server), you occasionally need to set flags in your store ("my state is dirty"). Forgetting to clean up a flag will lead to tears.

Same here, just switched to TypeScript today and it's quite nice. Not as nice than Elm in terms of tooling (those errors are much more helpful than the TypeScript one and js of course). I guess it depends whether you want the React community or don't mind a smaller one and a functional language.

Elm is a much, much smaller community than React. You won’t find as many libraries and ready-made components in Elm as you would in React. On the other hand, when there is an Elm library for something, it’s often of very high quality.

The learning curve is not terribly steep, compared to Haskell. There are a lot of good resources, and many friendly people on the mailing list to help you if you decide to learn Elm!

Haven't tried Reflux but I would recommend trying Redux before it. It is heavily inspired by Elm and has been very pleasant to work with. Reflux also bypasses the 'unidirectional data flow' part of Flux, which gives you added convenience for some things at the cost of more complexity.

I gave a talk going through this very conundrum. :)


I used to be a Reflux fan myself, but baobab (Om architecture) has scaled much better for us, in terms of code as well as devs who are new to React/Flux.

My first thought on seeing this post was "Oh wow, people are still using the elm email client". I guess I'm getting old.

hehe, I see this every time on an HN post about a new Elm release. At some point I'll have to look into that old email client, I'm curious what people are talking about.

Apparently the web site is having some issues?

Google cache:


If Elm had a dedicated library for io with Postgres functions (stored procedures) would then become very attractive to my company, for a very ambitious project we are developing. we store all state and logic inside db safely firewalled by stored procs, so i'm looking for UI focused language/ toolset that is productive, functional and produces atractive ultra reliable, performant html js. I don't feel good about the Sencha tools, my team currently uses, so I'm looking around for alternatives. ur/web looks very interesting aswell but the limited adoption with only 1 albeit genius developer, is a bit offputing

I don't understand, elm is for your browser based application, which can't communicate with postgres anyway except through a web server sitting in the middle.

That's true, although I see no reason Elm couldn't be compiled to server-side JS running in Node.

I'd love to see some full stack solution that would abstract away separation between backend and frontend (like Meteor perhaps) using some sane programming language and architecture.

Having built lots of SPAs and APIs serving as a backend for them I always feel that what's really relevant is modelling your data and domain logic (which tends to happen on a server side) and the UI consuming this data on the other end. Everything in between – endpoints exposing the data on the backend, frontend machinery to pull that data into client – seems to be totally arbitrary and implementing it is nothing short of a grind.

Applications are open for YC Winter 2022

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact