Hacker News new | comments | show | ask | jobs | submit login
Elm for the Front End, Right Now (bendyworks.com)
101 points by listrophy on Nov 23, 2016 | hide | past | web | favorite | 77 comments

I really want to like Elm. When I'm writing JS/React code, I sometimes think "this would be so much nicer in Elm!" - especially for architectural issues. But the few times I’ve actually tried doing something in it, I find that the parts of what I want to do that fit cleanly within Elm’s walls are really nice, but the parts that don’t quite fit get hard quickly. Suppose I want to do something with the DOM that doesn’t quite fit into virtual-dom’s model -- I suddenly have to make a complicated JS interop and work around things to get at the raw DOM node... whereas with React I can just hack something together, try it with users, and learn that I should actually be doing something completely different anyway. Or maybe I don’t actually know yet what I want to have happen in every possible condition? Maybe I feel this way because I just don’t have enough experience, but it may be a fundamental trade-off involved in how Elm makes it hard to do things wrong.

Has anyone had some positive experiences with prototyping / rapid design iteration with Elm and can share some tips / encouragement?

Similar experience. Once you get to grids and calendar controls it is a hassle with no clear path.

I think two things are require for to solve this:

1. Some way to make it easy to drop in components into an existing view. Global state makes this hard, but it may be possible with some of Haskell's funky features, or even just type classes.

2. With the above we just need people to write some basic controls for Elm and give them more features. We need an ecosystem.

They really seem to be staying in the global state camp. I find it impractical too, but it would make their "time travelling debugger" and other similar tooling stop to work if components could have local state.

Global state is OK, but I think we need language features or sugar to help embed the components. If those language features can be nice mathematical generic features like you have in Haskell that is better.

An example is a calendar control, in a grid control in a tab. You click right to go to the next month. That event needs to be bubbled through layers of boilerplate code to direct it back to the calendar's view.

Also another consequence is that the model is a mix of business data and UI state data. The selected month shouldn't affect the business logic, but it is bundled with THAT data which is annoying.

Not sure what the solutions are though.

While it's easier to bang out code with React, you have to acknowledge the massive downside of that flexibility: you have zero guarantees that your code will work properly. Even if you use Typescript or Flow you still you won't have the guaruntee that your code accidentally "fire the missiles", because JavaScript is not a pure language.

I totally understand that DOM access is a pain point for Elm developers right now. I often run into that issue myself. But declaring a port is a small price to pay for the all that the Elm compiler gives you. When I have to refactor a React/Redux app, I absolutely dread it. With Elm, I love it, even if the project is older or unfamiliar.

Yes, purity goes an extra mile; but refactoring a functional typescript codebase (and I'm not talking about codebases written with typescript like if it was javascript) is also really pleasant, especially with the flawless Atom/Visual Studio typescript support.

Similar experience, especially if your ambition is to have a very neat application with rich components. Elm elegantly solves 70% of the problems, it's awful at the other 30%.

If we have to use JS via ports (and it has to be asynchronous! dang) to achieve complex things anyway, why not use typescript, which can do absolutely everything you need without the language context and async switch?

Is the virtual/real DOM chasm difficult to traverse in vue.js?

I wish they would stop making changes just for the shake of change. E.g. Up until 0.17 most code examples where using the prime ' character.

With 0.18, Evan decided that using prime is bad taste, so he decided to break any code that uses it.

Sure, it is not a big change, but it means they are not respecting user's time and it is a sign of things to come.

Sorry for the rant.

Edit: I hope my reply doesn't get misunderstood. I love Elm and use it in all my side projects. I think it made wonders for introducing new people to the ML world.

Edit2: Sorry, didn't meant to make so much fuss about it. It is indeed a small thing.

Just a reminder that 'elm-upgrade' [0] should handle this automatically.

[0] https://github.com/avh4/elm-upgrade#elm-upgrade

I agree... I wish we still had the prime character. But since Elm isn't at 1.x status yet, that earns me an "irritated smirk" rather than a table-flip. :)

Yes, I am not saying it is a big thing. It's a small thing in itself, but breaking backwards compatibility for no good reason is huge red flag for the future.

> breaking backwards compatibility for no good reason

I'd say reducing weird syntax is a perfectly good reason. How is doing this while offering an easy migration solution in an early stage language a "huge red flag"?

A prime as an identifier constituent is not "weird syntax". The ancient C tradition of only allowing [_[:alnum:]] characters in identifiers is pretty pointless anyway. I really wish more languages would allow question marks and exclamation marks (and everything else), the way Lisp and Scheme do (e.g., https://docs.racket-lang.org/guide/syntax-overview.html#%28p...)

There's a very good example in C++ of how this causes problems, where vector::clear and vector::empty are much too easy to confuse (which one of them deletes all elements, and which one of them checks if a vector is empty?). Replacing them with clear! and empty? (or is it clear? and empty!) would be a huge improvement. Whenever a language moves away from arbitrary legacy restrictions, that's a good thing.

The problem is that prime (as it's used, anyway) doesn't carry any meaning the way ? and ! (as they are used) do in Scheme, it's just used for "I couldn't bother to think of another name". Enabling clearer names is great, but the language allowing primes in names was accomplishing the opposite of that.

I think that's a coding style decision, and shouldn't be part of language specification. I certainly don't feel about primes the way you do: having a function f and a function f' usually means they are sort of similar with some specific difference between them, definitely not "couldn't think of a better name". E.g., in haskell a prime often denotes a strict function, it's a better convention than having f and f_strict. Plus, how are you going to decide which unicode symbols should not be allowed? It can get a little random.

It's definitely a matter of taste, but I feel like settling for "similar except different somehow" is the same thing as "couldn't think of a better name". I would much prefer f-strict because then I don't need to be familiar with the punctuation conventions of the codebase to know how it's different from f, it's right there in English.

Edit: Plus, then you don't have to wonder if that particular function follows that naming convention; prime meaning strict isn't nearly as universally followed as ? or ! in Scheme, for instance.

In Haskell it's sometimes (often?) used for strict versions of functions e.g. foldl and foldl'.

it's a convention in ML languages, for a name whose value has been modified

> early stage language

I keep hearing this excuse, and to be honest I don't like it. On one hand we want to expand the usage of Elm, and have Elm be taken seriously, on the other hand when we feel like we use the "early stage" language excuse.

> I'd say reducing weird syntax is a perfectly good reason

I disagree with you on this, prohibiting the users from using the prime character has nothing to do with the language's syntax.

> On one hand we want to expand the usage of Elm, and have Elm be taken seriously, on the other hand when we feel like we use the "early stage" language excuse.

If I didn't know what changes we're referring to, it would sound like there was some critical change to the core functionality of the language.

Instead, they're removing one weird bit of syntax. It's not an excuse that it's an early stage language - it's acknowledging reality. And an upside to that reality is that making these types of changes won't upset nearly as many people as it would if it were a more mature language.

> I disagree with you on this, for me it is very worrying.

You're not explaining why. Here (https://github.com/elm-lang/elm-plans/issues/4) are three good arguments for removing it:

1. It confuses newbies.

2. It's an easy character to miss.

3. It's easy to migrate away from it.

What are your arguments for keeping it besides the fact it's already there?

> it would sound like there was some critical change to the core functionality of the language

No, I acknowledged early on, and many times, that it is a very minor thing. My only concern is that it is worrying for the future. (Using the word huge in the "huge red flag" was an exaggeration. I shouldn't have done so).

> 1. It confuses newbies.

Remove it from core language then. Having the prime character in my code, doesn't confuse anyone but me.

Is a language that allows Unicode characters for variable names confusing for newbies?

> 2. It's an easy character to miss.

Again, it is in my code.

> 3. It's easy to migrate away from it.

That's not an argument for removing something.

Again, my point is that is has to do with personal taste, yet Evan decided to force it to anybody who uses the language.

He could have very easily enforce it to core packages, and nobody would complain. But forcing it on my code, is worrying.

> Remove it from core language then. Having the prime character in my code, doesn't confuse anyone but me.

Until you take your personal style to Github, or coworkers...

Evan is doing a pretty good job at managing Elm – in fact I don't know any other language except maybe Swift where the rollout is planned to such a depth.

If coworkers are unhappy with it, they can (and should) make guidelines for acceptable syntax. This is no different than using camel case in Java instead of snake case (or using the $ in identifiers, which is extremely rare). If it's a problem to use it in my code on Github, you can always use somebody else's code or fork mine to change it. Maybe we should use the compiler to force every line to have a comment so we don't have any undocumented code on Github too?

This is what I find troubling about Elm.

The creators see it appropriate to enforce their strange preferences with dubious reasoning. The enforcement (in standard Elm format) of a 4-sized tab[1] is just another example.

Like you said I'd not have the language community enforce what is acceptable down my throat, and that conflict of preferences within a team is best solved by making style guidelines instead of having the language community spoon-feed an authoritarian preference.

[1] https://github.com/avh4/elm-format/issues/210

I completely agree with you. Evan isn't happy just controlling what packages you can publish that use the native api on package.elm-lang.org, or what you can do in the language since the removal of signals, he wants to control even minute things like whether you use a fucking prime in a function name in your own code. It's ridiculous.

Before you reach a 1.0, you should be able to break backward compatibility for any and no reason.

Most likely the reason is that you want to make something that you yourself are proud of or at least satisfied with.

Unless you're being paid for the project, satisfying your psychological goals should be the prime point of pre-version 1.0 software.

It's not at 1.0, there's no promise about preserving backwards compatibility at this point.

See my reply to the other thread.

1. If it is not ready for prime time, maybe we should stop promoting it?

2. React was 0.14 up to a year or so ago. The number doesn't mean anything.

> prime time

Apparently, prime time came and went :)

> If it is not ready for prime time, maybe we should stop promoting it?

It's about as ready as the impression it makes: yes, you can use it for project. But you may need half an hour every few months to update.

> Apparently, prime time came and went :)

:D. Pun was not intended!

People are excited by it, and managed to deal with prime-ageddon without any major headaches (it's like basic regex search and there's even an update tool, come on).

I actually think that's a terrible idea. `0.x`v versions are precisely the time to try and get this stuff in, before you end up locked into it forever.

I think that Elm is a fundamentally good language, being catered towards JS developers will hopefully attract more of them to FP development. However, I feel that the language is too restricted compare to other FP languages (Haskell, Purescript, even Scala), as a result you often need to write too much boilerplate and the Elm architecture doesn't seem to fit nicely for all kinds of components.

Which is why for now I'm looking into Purescript and GHCJS which support features such as Rank N types, generics, typeclasses, functional dependencies/type families. Even though I don't use many of those features directly, I do benefit from libraries that depend on them.

Speaking of Elm I liked this video from Erlang Factory about using Phoenix and Elm together. They both have a functional flavors so I think it might appeal to same people:


The first half is about Phoenix, the second about Elm. I don't know much about front-end stuff but I did like the Elm bit as an intro, especially the debugging and nice error messages part.

From what languages is Elm inspired? I've a Java/C#/PHP/JS background and I feel really uncomfortable with Elm syntax.

Completely logical. Java, C, PHP are said to be algol descendants. In two words: curly braces. JS wasn't supposed to but ended up curly because social trends are that strong. Now imagine JS function being the only thing you use, then that language users and designers evolving a syntax for typed js-like functions, rince repeat, you get ML, Haskell, Elm.

In time your brain realigns, depending on how much you appreciate the functional style or not.

Not quite. ALGOL doesn't have curly braces, just BEGIN and END blocks.

  EBCDIC ARRAY E [0:11];
    WRITE (F, *, E);
I've heard it said that the languages you mentioned are inspired by C's syntax.

Wow, couldn't be more wrong. It's indeed C family (BCPL, B). Thanks a lot for the note.

Well, I wouldn't be so hard on yourself. IIRC (and I hope someone corrects me if I'm wrong), algol introduced block scoping. Whether you use BEGIN/END or {/} I think is a pretty minor point.

C has braces to introduce a new scope. The irony is that JS (until recently) didn't have block scope. It just has braces :-).

Now this is where it gets screwy. You are supposed to (but don't have to usually) add a semi-colon on the end of each statement in Javascript.

a = 52;

This has a semi colon because it is a statement. There is another construct called an expression. An expression is anything that can evaluate to a value. An statement can be an expression (the statement "a = 52;" is an example of that because it also evaluates to 52 and is thus an expression). But there are expressions that are not statements. Here is an example of an expression

(5 * 27)

It evaluates to a value, but doesn't do anything so it is not a statement. Usually in computer languages, if "statements" are actually expressions. So you can say

if (1>0) {"Yay"} else {"Boo"}

evaluates to a value ("Yay" in this case), but doesn't do anything in and of itself. The blocks in the braces may contain statements, but the if is an expression, not a statement. Note the lack of semi-colon. Again, presumably because it is an expression, not a statement.

You can try the above in Node and it will indeed return the value "Yay".

a = if(1>0) {"Yay"} else {"Nay"};

In this case the variable a should be assigned the value "Yay", because the if expression evaluates to a "Yay". For some strange reason (that I don't understand), Javascript (or at least Node, when I tried it) does not accept that. It gives you a syntax error. You can not use if "statements" as expressions in Javascript (which sucks quite a bit).

All of this to say that Javascript appears broken to me, no matter what geneology you assign to it :-D. I personally really like programming in JS (or actually CS), but it is a beast unto itself, I think.

I'd welcome comments illuminating this issue if I've made a mistake with the above! As I said, it's easy to do.

True but my algol mention was strongly on syntax not semantics (big part of algol contribution).

>You can not use if "statements" as expressions in Javascript (which sucks quite a bit).

It does indeed, and it leads to some ugly code:

a = function() { if(1>0) { return "Yay" } else { return "Nay" } }()

You can also write:

a = 1 > 0 ? "Yay" : "Nay"

Because I really like syntax like Haskell (the type signature is much clearer especially in generic code compared to Java or Scala etc. for example), I'm curious, what is so uncomfortable about the syntax?

The lack of parentheses around function calls makes it hard for people not familiar with ML-style languages to tell where the function calls are and what the arguments are to each function call.

There is a wide variety of syntax among mainstream languages, but basic function calls are pretty much all the same.

Take a look at Reason [1] for an example of how a functional language (OCaml in this case) can be made more familiar.

[1] https://facebook.github.io/reason/

Or maybe people could just become familiar with ML-style languages? The basic syntax shouldn't take more than an hour or two to pick up.

Well sure, but you could say the same thing about Lisp.

Well they're both the lambda calculus, Lisp just had parentheses.

Does lambda calculus have character strings, structures, exceptions, symbols, mutable variables, quoting code as data, macros and three different kinds of object equality?

it does have symbols

Does it really?

Some of the algorithms for reducing lambda expressions are symbolic, like, say, alpha reduction. But they are not done in lambda calculus itself, as far as I can see; they are done on lambda calculus (by the mathematician, or a machine for manipulating lambda calculus terms).

Analogy: just like ordinary algebra doesn't have symbols; but of course mathematicians work with symbols and so do computer algebra systems.

Since lambda calculus is Turing complete, it can of course represent lambda calculus manipulation (via Goedel numbering of lambda terms and then working with their arithmetic encoding as Church numerals, or whatever).

Ruby has optional parentheses around function parameters (usually it's recommended to avoid parentheses if possible). Shells have no parentheses around command arguments. These languages are mainstream and no one complains about this.

Of course, if we adjust "mainstream" so that it refers to that set of languages which have pass-by-value, strictly evaluated arguments, with no implicit currying, then your point is nearly self-evident. :)

Yes, I agree, that took me also some time to get used to when I dabbled with Haskell and I looked at more complex programs.

when I spoke with Evan (you can usually meet him at the Elm SF meetup) I believe he said Elm was inspired more by OCaml than Haskell. But since many people might have heard of Haskell more than OCaml, Haskell is a better general answer.

The syntax is closer to Haskell than Ocaml.

Foe example types in Ocaml usually start with lower letter.

Also Elm has "Maybe", just like Haskell, instead of "option" of Ocaml.

Also in Elm, like in Haskell you would write "List Sometype", while in Ocaml it is "sometype list".

Yeah the syntax is clearly Haskell, the semantics are more ML-ish.

Haskell, ML langs.

Haskell but is very reminiscent of F# with the >> amd |> operators (which I prefer to . amd $). Although you could name them that in Haskell too.

Yeah, it seems like a step back in readability... It's not at all intuitive and once I figure out what its doing, I can't find a reason for it.. Lisps are hard to read, but there are at least a few reasons for the syntax (not that i like them) ... This just seems... weird and unusual for no reason...

Have you spent much time with it? Like all things, you need to learn before you understand, and then it becomes clear.

I've written a fair amount of Elm, and I still find it awkward. One issue is that I feel like I end up having to go back and add in brackets more than I would with the C-style syntax. I'm not sure if that's just the way I think thanks to being used to that, or an inherent problem.

The main issue really is that I think it's harder to read, as it's less clear what is being used where. The explicitness of the C-style makes it easier to see what goes where.

Thats kinda the point... with the vast array of languages out there, that are performant and powerful and very well established, why should anyone suffer through the learning curve? what value does the language offer to make that worth the effort?

Well, evaluation in these languages is more transparent. The syntax is basically the lambda calculus, so once you've actually learned the language it makes a huge difference. I'd try reading up on "referential transparency".

One thing that can help with the discomfort is thinking about it as patterns. The = operator isn't for assignment, it's an assertion of equality. Reading the docs carefully helps immerse you in the syntax as well.


Yikes, you should branch out more.

in case anyone's wondering, it performs about the same as 0.17:


interesting that Elm's own benchmarks has it handily beating the frameworks it performs worse than in these.

I remember evaluating Elm and ClojueScript as an alternative to ES6 about a year and a half ago. Eventually I had to decide against both as we absolutely needed to render parts of our page server side (Google saying they'll index SPAs is a joke.)

If I'm not mistaken this wasn't possible in Elm back then, and felt uncomfortable or even hard in ClojureScript. Has that changed?

To be fair if I started a new project like the one I'm working at now I'd much rather use server + template for most pages and add interactivity through JS once it boots up.

In clojurescript we have RUM (another lib on top of react) where you can render your HMTL on the server (without using node, just on the JVM). It's also blazing fast and works very well.

why not flowtype/typescript+js es6+react+redux/mobx?

currently a pretty nice reactive mobx-state-tree is on the frontpage of hn.

I'm quite sure it's exactly for that reason, not having to choose between

- Flow vs Typescript

- ES5 vs Babel

- React vs Angular vs Vue vs jQuery

- Webpack vs Rollup

- Redux vs Flux vs Mobx vs React states


Plus, probably lots of dev prefer Elm's syntax and design.

This is exactly the reason I'm interested in Elm. My team has gone from React to React + Flux to React + Redux to React + Redux + Immutable to React + Redux + Flow in the last 2 years. That's a _lot_ of change, and we're not even talking about the build tool side of things with Browserify, Babel, Webpack etc.

In Elm I can see the same kind of framework simplicity that attracts me to Go.

Parent is absolutely correct.

I can either work on Elm and deal with breaking changes like variable declarations (as noted above), or work on my React/Redux app, where I'm halfway refactoring from ReactRouter v3 -> v4 and Redux Form v4 -> v6, both of which are painful upgrades. Which would you rather deal with?

Typescript has types, but it's the same terrible language underneath.

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