Hacker News new | ask | show | jobs
by spuz 3671 days ago
This kind of comment about Elm is quite hard to understand without context. Have you ever used a typed language before? Have you ever used a pure language before? Is there something special about Elm that gives you this kind of benefit, or do other languages do the same thing?
7 comments

Not the author but I've had similar experiences. I haven't used Haskell or OCaml in my day job (though I would like to if given the opportunity). I have written some trivial and slightly serious programs in both of these languages. I've even worked up a few small programs in Agda.

Elm, IMHO, is in a class of its own. There's a strong focus in the design of the language to be usable and friendly to the developer. The focus on structural typing, the error messages, and the tooling all go a long way to bring the developer from beginner to expert with as little friction as possible.

In contrast I find this is the biggest hurdle for Haskell and OCaml. It's simple enough in either language to get started but there's a steep learning curve to becoming productive and the tooling, documentation, and even the design of the prelude libraries are the largest stumbling blocks for transitioning from an intermediate developer to an advanced one.

update: grammar

> Is there something special about Elm that gives you this kind of benefit

Evan cares about compiler messages, and as a result Elm's compiler errors are the most friendly, readable, helpful and actionable messages I know of, even compared with projects with good error messages like Clang or Rust.

Most other typed functional languages don't come even remotely close, best case scenario is they're fairly complete once you've learned to decrypt them, Elm's compiler error messages have almost no learning curve. Though it may help that Elm is wilfully limited abstraction-wise.

I've used typed languages, and pure ones, but what I've found to be really special about Elm is that the compiler is super helpful. This also makes learning the language really enjoyable, as you've got someone helping you along. :)
Haskell does the same thing.

EDIT: I didn't mean to say that Haskell is as easy, or that the error messages are as good. I just mean that the error messages can give you a nice reminder of what you were working on, which I believe was the point of this post.

No, Elm is definitely less complex and generally targetted for newcomers to the FP and pure world.

In haskell there are like a 100 ways of doing anything and it's very hard (for me at least) to figure out where even to begin. Elm tries to reduce options and lets noobs like me get going.

It seemed to me like elm reduced options all the way to zero for way too many things. Trying to do basic tasks that are trivial in ocaml and haskell ended up with me giving up completely when trying in elm. Just generating random sequences was ridiculous.
For what it's worth, generating random values is slightly easier with the introduction of subscriptions in 0.17. If that's the version you tried, it would be nice to see why you think Elm is unnecessarily complex compared to Haskell (which is also pure) when it comes to generating random values.
>If that's the version you tried

No, it was a couple years ago.

>compared to Haskell (which is also pure)

But which has both a real type system and a useful set of base libraries. The lack of basic stuff like monads is really painful in elm.

Really? Having dipped my toes in both I certainly felt like the error messages of the compiler to be very different. I could be way off.
Haskell had poor error messages last I tried it. Have they improved?
Haskell has... precise... error messages. As I learn more about it, the errors are become more useful, and driving my development in a similar way to with Elm, however with Elm the learning curve is far shallower and the compiler helps you up it, whereas with Haskell I'm always just googling types to figure out what the compiler is trying to tell me.
Many of the error messages become clearer with experience, but this is mostly due to developing an intuition for what is actually wrong with your code based on the error message you see, not due to the helpfulness of the error message. Often the actual source of the error is in a different place than what is reported. Consider what happens if you mean to concatenate two strings but forget to put `++` in there:

    Prelude> "foo" "bar"

    <interactive>:3:1:
        Couldn't match expected type ‘[Char] -> t’
                    with actual type ‘[Char]’
        Relevant bindings include it :: t (bound at <interactive>:3:1)
        The function ‘"foo"’ is applied to one argument,
        but its type ‘[Char]’ has none
        In the expression: "foo" "bar"
        In an equation for ‘it’: it = "foo" "bar"
Yikes. Even worse, consider a similar situation with numbers:

    Prelude> 1 2

    <interactive>:2:1:
        Non type-variable argument in the constraint: Num (a -> t)
        (Use FlexibleContexts to permit this)
        When checking that ‘it’ has the inferred type
          it :: forall a t. (Num a, Num (a -> t)) => t
Also the parser errors in Haskell are terrible. That the community has so long put up with "parse error (possibly incorrect indentation or mismatched brackets)" is a marvel to me, and is one of the most irritating errors to fix because of the (at least apparent) simplicity of improving it.
And that is exactly why people love Elm:

  > "foo" "bar"
  -- TYPE MISMATCH --------------------------------------------- repl-temp-000.elm
  
  You are giving an argument to something that is not a function!
  
  3|   "foo" "bar"
             ^^^^^
  Maybe you forgot some parentheses? Or a comma?
Also

  > "foo" + "bar"
  -- TYPE MISMATCH --------------------------------------------- repl-temp-000.elm
  
  The left argument of (+) is causing a type mismatch.
  
  3|   "foo" + "bar"
       ^^^^^
  (+) is expecting the left argument to be a:
  
      number
  
  But the left argument is:
  
      String
  
  Hint: To append strings in Elm, you need to use the (++) operator, not (+).
  <http://package.elm-lang.org/packages/elm-lang/core/latest/Basics#++>
Interesting! Thanks for the example.

How do compiler errors look in Elm with generic functions involved, about which the compiler doesn't have any helpful hardcoded knowledge? (I.e. no "+" or strings involved).

The first error message is good: it helpfully includes the exact expression that craps out, and it means, matching intuition about how Haskell should be compiled, that the expression "foo" "bar" could only make sense if "foo" were a function from [Char] (i.e. the type of "bar") to some type t, but unfortunately "foo" is a [Char]: everyone should understand it easily, even if gratuitously introducing other names (it and its type t) and details about the compiler making up type equations is highly inelegant.

The second error message, on the other hand, proves that the first one is a lucky accident.

Everything you say is true, but it took me about 90s of staring at the Haskell error before I parsed out exactly what it was objecting to, even though I knew exactly how the code was broken. Whereas it took me no discernible time to understand the Elm error messages. Some of it could be that parsing the Haskell message primed me for the Elm message, but it doesn't seem that way to me.
>The second error message, on the other hand, proves that the first one is a lucky accident.

No, the second error message just shows that there's more options there so the error message is vague and not very helpful. The first one is not an accident, it is the standard type mismatch error.

Not saying many Haskell compiler errors are obscure, especially for the uninitiated, but the particular error you picked as your first example is perfectly clear.

Haskell is telling you 'you tried to apply a string literal to an argument as if it were a function, but it's not! It's a string literal. By the way, the string I'm talking about is "foo", which you tried to apply to "bar" in the expression "foo bar"'.

Yikes? It seems pretty helpful to me :)

Your second example is better, though.

Well like I said, once you see enough of these error messages you get a clear idea of how to parse them and understand what they're "really saying". But on first glance, and in particular for newcomers, the error message is rather arcane. And of course, in this instance it's quite straightforward because it's a very simple expression, with a rather clear problem. But consider when the error might be buried in a much more complicated expression, or the fact that it's not a function (or is a function, when you expected otherwise) might not be as clear. For example a curried function that has too many or not enough arguments applied.

Also, although from a compiler's point of view it might make sense, the wording "The function ‘"foo"’ is applied to one argument, but its type ‘[Char]’ has none" doesn't make sense. It's clearly not a function if it doesn't take an argument. The same error message would be far clearer if it said something similar to "The expression ‘"foo"’ is being used as a function, but it is of type ‘[Char]’".

Also these are just two examples I rattled off the top of my head; the fact is that while the compiler is incredibly helpful in making sure your code is correct, it's less helpful in explaining itself. But, I also realize that producing good error messages is hard, and (I assume) significantly less interesting to many on the GHC team.

The output contains all you need, yes, but it would be nice if what you typed was added to the output. You wrote out a much more user friendly version.

Someone posted the output from Elm, which does this: https://news.ycombinator.com/item?id=11848467

Edit: checkout the elm error message page here http://elm-lang.org/blog/compilers-as-assistants

I didn't think that ease of understanding was necessarily the point. My point was that once you do understand them, it sort of tells you what to do next.

That said, in a recent HN post somebody said that the latest version of GHC has better error messages, which I agree would be welcome, but I haven't tried it.

Without having used Elm that much myself: One of its features is its very user friendly error messages. I imagine the author is comparing with more dynamically typed languages, where when you leave your work in the middle of something, there's usually a bit of digging when reopening it and continuing work, which he contrasts with Elm, where the compiler is quite excellent at reporting your unfinished work (in the form of helpful type errors), allowing you to quickly grasp at what point in your program you were at.
Exactly what I wanted to ask. Can we mere developers have some context to it?
Haven't used Elm myself, but I assume this argument is based in large part on the strength of the Elm compiler error messages. For example: https://twitter.com/ID_AA_Carmack/status/735197548034412546
That's kind of amazing.
Here are some more examples, though are generally more basic errors: http://elm-lang.org/blog/compilers-as-assistants

Overall, I really like the approach of making error messages an important feature. We see them so often that improving them makes the developer experience much better, but I can imagine they're a less 'sexy' task to work on and probably much harder to get right than you'd expect.

It's just "Elm is good and other languages are bad/not as good". I try to be live-and-let-live about such things.