Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
Elm 0.14 – Simpler Core, Better Tools (elm-lang.org)
231 points by teamonkey on Dec 10, 2014 | hide | past | favorite | 70 comments


If you're interested in Elm but don't really know what it's about, I highly recommend Evan's Strange Loop talk, "Controlling Time and Space: understanding the many formulations of FRP."

It will help to already have a bit of background in functional programming.

https://www.youtube.com/watch?v=Agu6jipKfYw


Started watching, the slides animations are a nice enhancement. Are they perhaps written in elm?


He works for a company called Prezi whose product is the slideshow software he's using. God, I sound like a stalker, don't I.


The Elm website is blank without JavaScript enabled. Here's a script to extract the Markdown in the given page and optionally format it without having to enable JavaScript in the browser:

https://github.com/pflanze/de-elm

(Edit: here's a copy of the content of the linked page: https://github.com/pflanze/de-elm/blob/master/examples/annou... . Tell me if you don't like this and I'll remove it again.)


I don't know why people always bring this up. Elm is a compile-to-JS language. The website is implemented in Elm.


I understand both points. Or more precisely, after viewing the source of the page, I made a good guess that the reason this is js only is that Elm, if I remember correctly, is the language that formats pages without (just) relying on CSS, by using JavaScript, thus I'm totally understanding; although I'd like to make the point that I only got there since I had seen Elm discussed previously, and looking at the regular code in the source and hence guessing that it's compiler output. Perhaps it's not wise for the creators of the language to presume as much.

So, there's a practical point to this, which is that I wanted to read the page, and a mixed practical/political point which is that I don't want to enable JavaScript if I don't absolutely have to. So I sat down and figured out what can be done...


Basically, I agree with the dissatisfaction with JS-mandatory basic, informative pages.

I'm sure this will cease to be useful at some point, but for the moment, I find that some of the time, running the URL in question through Google Cache produces a useful view.

Of course, Google properties themselves increasingly insist upon JS, even for basic "read-only" views. At least I have some confidence that Google is performing some measure of vetting their own JS against particularly the security problems that most concern me.

Here's the OP URL, via Google Cache:

http://webcache.googleusercontent.com/search?q=cache:http%3A...


Why doesn’t elm provide text content separately in a machine-readable format, for example in a set of hidden HTML elements?


<noscript> is basically designed for this, I'd favor it's use too.


JavaScript is machine readable.


The benefits are actually much deeper though. Now that we know exactly how the API has changed, it is possible to automatically enforce strict versioning rules. If there are breaking changes, the new release must be a major version bump.

This is very interesting to me. It demands consideration: do we need a person to manually bump the version anymore at all? If you can statically verify that a change meets the criteria, couldn't the package publishing process autoincrement the appropriate version segment and be done with it?


there are probably cases in which you want to change the version independently of API changes, i.e. "going stable" (0.x to 1.0), major internal changes, new interfaces with deprecations of the old ones etc.


Good point, you still need an escape hatch to bump a version segment higher than the minimum necessary one, for many reasons.

I'm not sure I agree that the phrase "going stable" really applies to a semver project. The most stable release would just be the highest number in each segment. Version 1.0.1 is almost by definition going to be more stable than 1.0.0, since the changes are only backwards-compatible bug fixes. At least that's my understanding of semver.


semver has a special case for 0.x, which is basically "before 1.0 there are no guarantees". In their words:

> Major version zero (0.y.z) is for initial development. Anything may change at any time. The public API should not be considered stable.

(Yes, this means that you can use 0.x and declare yourself "semver compatible" and break on any patch release)


It seems doable to differentiate additions from (breaking) changes if all the API is statically defined. It would be nice to even have the feedback on larger changes.

That being said it's possible to change a library's behaviour without touching the API. Consider the following diff:

    -add a b = a + b
    +add a b = a - b
Granted the example is simplistic. With the API versioning system in place the author should have renamed the method and would have gotten the right result. It's just to show that it wouldn't be a silver bullet.


My attitude towards developer tooling tends to be: build the tools first for the experts, and second make sure the are learnable. I can't stand professional tools that are built primarily for new users. Englebart's violin [0] and all that.

That said, it might be the case that removing the responsibility of versioning from experts would make them less concerned about the ramifications, and less likely to notice when they make a change like this one (well not this one exactly, but one similar but more reasonable).

You really do need tests in addition to static analysis to be sure of these things.

[0]: http://www.loper-os.org/?p=861


I think it has as much to do with standardization as ease of use. This way, if there are multiple experts, they don't each do it their own way.

Plus, it gives a degree of reliability to those using the packages, which is something you can't necessarily count on in Haskell right now.


What is the point of changes like [] to List, mod to %, . to << and >>? Is it just aesthetics?

When I looked at Elm it was really similar to Haskell. After I learned a bit of Elm I dove into Haskell. Now that I'm coming back to Elm I'm having problems because I confuse this different syntaxes many times.

I hoped they could maintain the language more similar to it to make the switch between them easier.


Personally, I am overjoyed that Elm is taking steps to make it's aesthetics more approachable to the non-Haskell crowd. Haskell is wonderful, but it has a learning curve that is steep enough to ward off the vast majority of programmers. A big part of the curve is that Haskell has a vocabulary that presumes a familiarity with decades of research that frankly only a very small population is familiar with. In that context, I'm sure "lift" made sense for the Elm thesis. But, without that context, "map" makes a lot more sense to me and to a lot more people.

I'm hopeful that Elm will help bring Haskell's ideas to a wider audience. After those ideas become familiar, I fully expect a large crowd of them to find Haskell's highly efficient syntax for expressing them to be very enticing. But, getting people to that point is going to require a lot of considerations to ease the JavaScripter -> Elmer -> Haskeller transformation.


Yes, Elm is a gateway drug to Haskell.


I expect that at some point, someone will write a Elm -> Haskell thing (like Elixir -> Erlang).


I'm pretty sure I read about someone writing this at some point, but I couldn't find it.


I personally find all the changes really nice. (<|), (|>), (<<), (>>), are far more intuitive compared to the Haskell operators for example. Yes, it's just syntax, but usability is important. As an aside, Idris uses (:) in type signatures, and doesn't have a lift function in its standard library (it just leans on a genereralised map function).


The only reason why Haskell uses (::) is because they wanted to preserve (:) for lists, thinking that list operations would be more prevalent than type operations. That ended up being a poor bet, as it turns out.

(:) is very standard notation for "has type" in type theory.

Also, all of the mapN functions exist in Haskell and Idris as applications of the Applicative typeclass.


Yes, aesthetics. Here is another one:

: and :: are reversed.

They have no intention of making them more similar- in fact I was told there is going to be more subtle diverging happening.

Elm was really cool for me too at first, but these subtleties are just a pain. I am now using haste (haste-lang.org), which seems to have really come a long way over the course of its 3 year life span. I highly recommend it to those wanting to use Haskell as a front-end web development language.


Wow, haste is great. Thank you for sharing.


Completely agree. Not only these subtle changes but also the Evan's resistance to include common typeclasses and generally anti-intellectual attitude and rudeness have turned me off completely. Evan also plays favorites a lot and has a rather naive view of social justice (which he views himself as some kind of champion for).

Purescript has now become my alternative but I will take a look at Haste (ghcjs may be another possibility to look into).


Concerning [], many people regret that there is a special syntax for it in haskell


Have there been any performance improvements under Firefox? Almost every Elm demo that I've seen so far has been basically unusable under that browser. I've been told that the issue is some difference between Chrome and FF with canvas drawing... but regardless of where the fault lies, Elm is pretty much a Chrome-only technology until that gets worked out.


Someone please correct me if I am wrong but I believe the answer is yes. I believe this is the relevant PR:

https://github.com/elm-lang/core/pull/25

I believe the original improvements were done here: https://github.com/jwmerrill/elm-animation-frame

I modified a game I wrote to use the modified run time. I can see a huge difference between the two in Firefox.

Unmodified: http://jcollard.github.io/elm-flyer-old/

Modified: http://jcollard.github.io/elm-flyer/


Author of that PR here. It may help Firefox some, but in my experiments I'm still seeing that driving canvas animations with Elm performs much better in Chrome than in Firefox.

If there are any Firefox engineers reading this, maybe there is a good benchmark to be extracted out of this observation? I'd be interested in discussing this with someone. Feel free to reach out at the e-mail address in my profile.


Yeah, this is in for 0.14. I forgot to mention it in the announcement, but Jason deserves a huge thank you for this improvement!


Awesome. I like the name change from 'lift' to 'map'. Also, the public API diffs that the packaging tool provides looks very neat. Congrats to the Elm team!


It's nice to see that they have replaced Either with Result[0]. I wonder if Rust's Result type[1] was the inspiration? (not sure if there is prior art)

[0]: http://elm-lang.org/blog/announce/0.14.elm#making-error-hand...

[1]: http://static.rust-lang.org/doc/master/std/result/index.html


I started looking into Rust again while picking the term "union type" because of their choice to use the term "enum". I ran into the Result type in some code I was reading and it just made so much more sense to me as a new person learning the language. Basically, it made it self-evident to me that "a library for error handling should be named with error handling in mind." You will also see a Result type in some Haskell libraries so it's not unprecedented there.

I also got tired of explaining "the good result goes in Right, because it's 'Right'" like I'm endlessly telling a bad dad-joke.


Yeah, we used to have an Either type in the Rust std, but it was pretty much never used because we had Result.


It's possible, but it's really just a name change. And the `Either` monad is used almost entirely for error handling anyway, so Result is a name that many Haskell/Elm users could come up with on their own.


But the variants being named `Ok` and `Err` match Rust's definition as well, which is why I'd like to second bjz's question as to whether there's some lineage behind this convention.


I decided to do some archaeology of my own.

Here's the first instance of what would become Rust's `Result` type (Oct 28 2011): https://github.com/rust-lang/rust/commit/c1092fb6d88efe51e42...

Note that the type is called `t` since the convention at the time was to name the primary type of a module `t` and then refer to the type as `modulename::t` (shows how far we've come, eh?). At this initial stage the variants are named `ok` and `error`. Also note that at this point in history Rust had had an `either` type for a while (https://github.com/rust-lang/rust/blob/c1092fb6d88efe51e42df...), which would later be removed as Result gained more traction.

Here's the commit where the `error` variant is renamed to `err` (Oct 28 2011, so the same day): https://github.com/rust-lang/rust/commit/2b62a80202e2855d47f...

Here's the first instance of `std::result` being mentioned in the mailing list (Nov 14 2011): http://article.gmane.org/gmane.comp.lang.rust.devel/891

Where the type itself is renamed to `result` (Mar 13 2012): https://github.com/rust-lang/rust/commit/b968c8e6cd362567bf0...

Where the type and variant names are capitalized in accordance with the current style guide (Aug 26 2012): https://github.com/rust-lang/rust/commit/0c6e470a257fc546555...

So this convention may very well have originated with Rust.


Also interesting to note in the context of the union type discussions below is the use of the `tag` keyword as opposed to the current `enum` for declaring tagged unions.


At one point we were trying to name every part of a union type in Elm. Calling things "tags" instead of "constructors" seemed quite nice, but ultimately, it seemed like we couldn't get the perfect name.


I always did like `tag`, but I think that's a fight for another year. :)


"Result" is a pretty opaque name: any value or type can be called a "Result", really. "Either" at least hints to the fact that it is either-this-or-that.

"Either" is IMO a nice counterpart to tuple types: one is a generic sum, the other is a generic product. People could complain that a tuple of ints are less descriptive than just using a constructor with a more descriptive name - like "Pair" or "Coordinate", depending on its intended application.

Having a specialized type for error handling makes sense, though.


It doesn't seem scalable though, because it only works for two types. It would be better to have some sort of structural union type (like Ceyleon).


But it's defined as 'Result error value', which means you can just make 'error' a union type, and now you have multiple kinds of exceptions. When you specify an error type, you're basically specifying all the types of exceptions that the evaluation can raise.


But it would be less descriptive from an API point of view. Which type is the return value? Of course we are now in the land of hypotheticals.


Elm really is fascinating... Am I the only one who thinks FRP is just a reincarnation of dataflow programming?

I'm learning Verilog in my spare time, because I want to implement a dataflow/FRP language in hardware. (People tried to build massively parallel hardware in the past to run dataflow languages... I'm pretty sure it's a good idea.) Should be interesting!


That's like saying Rust is "just a reincarnation of imperative programming". Dataflow is an extremely general category, there's a lot of room for important differences; describing something as "dataflow" doesn't really tell you much about it.


Well, of course I'm generalising here. It's just that, to me, dataflow and FRP look very similar. At least once you go past syntax and superficial things.

(I just realised you meant to say that FRP is a subset of dataflow. I agree!)


I used Elm for my Ludum Dare entry. As a first attempt using a functional language I definitely did many things wrong, but I found it very easy to iterate. Great language and I'm going to look into going further with it for game development.


Eh, that's a tagged union, but I think "union type" usually refers to untagged unions like you see in more dynamic languages such as TypeScript and Facebook's Flow. Tagged unions are typically called sum types. That is, searching for "union type" is gonna give you results about untagged unions or C style unions. I'm not sure this new terminology helps.


We discussed this to death on the mailing list, and this was definitely a consideration!

People searching for it online will very likely be searching for "elm union type" where they'll quickly find examples and docs. Furthermore, you can prefix the term "union type" with stuff like "closed/open" and "tagged/untagged" to start making finer grained distinctions as need higher degrees of precision. In Elm it is always tagged and closed, so in discussions within the community, adding those prefixes is redundant. Finally, if you start with the term "union type" it becomes easier to think about what an "anonymous union type" might look like (like OCaml's polymorphic variants or open variants) ;)

More broadly, if people do run into the term "union type" in other languages they will be building intuition in exactly the way I'd like: it's a way to use different types in the same place. Things happen to have this extra tag thing in Elm, but it's not so different than anything people do in JS or Clojure or Racket or TypeScript or C or whatever else. I think bringing that connection out is a major benefit of this naming choice. The goal is to feel really welcoming and friendly, and my personal preference is to build on people's existing intuition as much as possible. If someone comes from JS and does not see all the subtleties of this discussion immediately on day one, they are actually having a better experience because they can learn the info as it becomes relevant to their daily usage. Hopefully a much nicer learning curve!

I realize I am making a somewhat controversial choice, but the idea is that statically typed FP people are building artificial barriers by being sticklers about this, rather than just prefixing for precision. You may not agree with all this, but we thought it through pretty extensively, and that is the reasoning!


Depending on who you ask, there's another established meaning of "union type" when contrasting it against "sum type" in a safe context. Sum types are discriminated unions in which each constructor tag in the union is disjoint from each other member and all other types. In contrast, "union type" tends to imply that you can share constructors/tags between types.

For example Julia: http://docs.julialang.org/en/release-0.3/manual/types/#type-...

Typed Racket: http://docs.racket-lang.org/ts-guide/beginning.html#%28part....

Haskell: http://okmij.org/ftp/Haskell/extensible/#open-union

And many more.


This is precisely what I was describing, perhaps I wasn't clear enough. I should have mentioned Typed Racket as well. Unless you think this is different from what I said? Typed Racket's unions are just like TypeScript and Flow's unions, in fact TypeScript uses a similar occurrence typing algorithm where you need to do a type check in order to compute with a union value, e.g.

    if (isString(x)) {
      // only now can we call string functions on x
    } else if (isNumber(x)) {
      // only now can we call number functions on x
    }


OK, then we're on the same page regarding Elm's name choice: That is, it's a poor choice if they are actually disjoint unions aka sum types.

That said, forgive me pedantry for a moment: I think your use of the word "tag" is unclear. Typically, both sum types and union types must be tagged. If you think about something like the JVM, every object is tagged with a pointer to it's class. Untagged, or "tagless", objects are closely related to "unboxed" objects, but still not quite the same thing. The point is that the tag is something that can be inspected, switched on, etc at runtime. Where as a tagless representation does not require that runtime overhead.

It's possible to have a Union(int, String) or something like that where one type is typically untagged and the other typically tagged. If the compiler could eliminate the tag at runtime from context, then it would just eliminate the union and substitute the type with either int or String directly. So if it can't tell from context, it must actually make it a Union(Box<int>, String) so it can discriminate by tag.

Tangential: There is of course a trade off in tagless representations in terms of type system complexity and runtime cost. If you want to change from a List<int> (specialized list of machine ints) to a List<Integer> (nullable boxed ints), that's an O(N) operation to add the tags (and a more complex type system).


The thing is, "sum types" really only works if you're familiar with the analogy between boolean algebra and arithmetic (why OR becomes +).

Yes, they are disjoint union, but there's really no such thing as non-disjoint union in a statically typed language i.e. that's what makes it typesafe.


You can have "non-disjoint unions" in typesafe languages, you just will be no longer capable of distinguishing between the types of the members.


For the record, I voted for enum, like in rust-lang ;-)

This was going to be contentious no matter what. For what it's worth, Wikipedia (top Google result) seems to have a compatible story.

Luckily, it's just a conversation change. I think it will be fine, and net more helpful than damaging. The overall goals are intuition and accessibility.


  > For the record, I voted for enum, like in rust-lang ;-)
Funny, because there's actually a long, long history of debate around whether Rust should refer to them as unions rather than enums (and change the keyword correspondingly). :) Here's the most recent one that I know of: https://github.com/rust-lang/rfcs/pull/27

Swift seems to have followed Rust's example with its terminology here, so this issue is hardly settled. It may shake out such that `enum` is used for tagged unions where the variants are declared as part of the type (`enum Foo { Bar, Baz}`) (and hence the variants can't be shared between types, at least not without wrapping in a newly-defined variant), whereas `union` is used for tagged unions where the type is composed from multiple existing types (`type Bar; type Baz; union Foo { Bar | Baz }`).


Is anyone here using Elm in production ?


We've been using it to render schematic symbols and PCB footprints at CircuitHub.com (this has been going on for a couple of months). I'm testing it out in other areas of the product at the moment, so if all goes well additional Elm widgets might land on our site very soon.


Dreamwriter uses it, although Dreamwriter is still pre-1.0.

https://github.com/rtfeldman/dreamwriter


Here on PlayTacks, a sailing simulation: http://www.playtacks.com/

Nothing serious though...


For a second I had thought that someone had released an update for the Elm mail client. Color me disappointed (although I am more of a Pine guy myself, up to ~2006 at least).


That's pretty ridiculous. Literally the day after I start working on my Elm project in a couple months...

Anyway, the changes here do look pretty nice. Looking at the docs, it seems that they've added more examples, which is always appreciated! I still don't like the impurity that comes with the Signal.Channel, though... not that I have a better idea.


Very cool.

Interestingly enough, the dice is loaded. If you click long enough, you'll get an upside down V shape.


The dice aren't loaded, you're just seeing a binomial distribution[1][2] :)

[1] http://en.wikipedia.org/wiki/Binomial_distribution [2] http://hyperphysics.phy-astr.gsu.edu/hbase/math/dice.html#c2


There's actually 2 dices, so there are quite a few more ways to get a 7 than to get a 2

7 = 1+6, 2+5, 3+4, 4+3, 5+2, 6+1

2 = 1+1, 1+1


Or, the difference between 1d12 and 2d6 (roll of one 12 sided die, vs summing the roll of two six sided dice).


I must be getting old... I saw the headline and thought "Isn't the elm mail client at a higher version than that?"




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

Search: