For those of you who aren't getting the joke, this comment is not disparaging elm (I noticed a downvote earlier), it's a reference to later day terminal based email clients (two of which were 'elm' and 'mutt'). As in: http://www.guckes.net/mutt/vs.elm.html
Pine is not elm - my mind goes there right away too, but to be fair many three or four letter nouns will be reused like this (partly to save keystrokes).
I wish Evan allowed others to contribute to the official documentation. Right now Elm feels more like Evan's personal project than a project that is owned by the community.
Other then that, the community has done a good job of writing up documentation, and Richard Feldman is working on a proper book.
Agreed, there are some really good tutorials out there, way better then the official docs. But you need to go hunting for those, and a lot are a bit outdated, with the recent changes.
I'm really rooting for Elm, I so prefer it to TypeScript and alternatives.
That is the guide that helped me start, but is a long way to go until your first elm-only app. IMO the biggest weakness in the elm package ecosphere is that there is no proper solution to do url routing.
While elm-lang/navigation and evancz/url-parser get you 80% there, the remaining 20% cause a lot of pain.
I am very optimistic that in the coming months this situation is going to improve tremendously. If we all share more knowledge, tutorials, guides, the whole community will win!
Yes, I have not found a way to do url pasting in a way that looks clean and simple. It's the main thing keeping me from building big projects with Elm.
I think this could be one of the main challenges Elm face in terms of gaining support. I've been playing around with Elm the past week (creating a fun little web app to learn a new language) and the documentation would likely keep some developers from pursuing the language much further. What helped me was familiarity with functional programming via Clojure, and component based web apps with Om and React.
I think the docs could use a chapter on functional programming and how that works in the land of ML languages, and perhaps a few walk through examples of some simple, but not overly simplistic, apps.
So far though I think the language is pretty interesting, but I've yet to do anything really fancy with it.
I really like the look of Elm --- to me it seems to hit the sweet spot of being enough like Haskell to be awesome while also being understandable by humans. It also fixes some of the rougher edges of the Haskell syntax; I vastly prefer Elm's record syntax to Haskell's, for example, which apart from being much cleaner and obvious also avoids some of the more common Haskell namespace traps.
The one piece I'm really looking for is server-side Elm, though. I've love the ability to write both my client and my server in Elm. I know there are some projects to allow Elm via node.js but they're still quite rough.
(Is anyone looking into transpiling Elm to Standard ML, so that it can be compiled to fast native code with MLton? Because that'd be, like, really cool.)
Agreed! While I do tell myself "right lang for the right job", I've come to the conclusion that I am lazy. :) So if Elm can run on Erlang/OTP like Elixir, that would be an interesting option for the webdev space. I don't even know if something like that is feasible, but I wonder someone's thought of such a thing?
Why not just use Haskell for the backend? It's really not much harder than Elm, and it's considerably more flexible and general. Of course, it's lazy, not strict, and you're totally right that records in Haskell suck. But my understanding is that strictness for Elm was chosen mainly to overcome issues with FRP, which it's now abandoned. So I'm not sure if that difference matters anymore.
There's several reasons, one of the simplest (but not the most trivial) being that I can't share code between the client and the server. For example, data validation. I did a tonne of programming on GWT back in the day, and this was something it actually did well.
Most of the other reasons boil down to Haskell not being Elm --- they work in different ways and solve problems differently. There's always going to be impedance mismatch between the two. (Do I solve this problem with monads or with state-mutation functions?) This is going to use up valuable problem-solving bandwidth which I'd rather spend making the project more awesome.
The question was about using haskell on the back end. Also, previous attempts at sharing client and server code in other langs are sophmoric at best. In reality, there will always be a boundary that requires differences in front end and back end code.
> Haskell is not Elm
Doesn't answer the question, circular reasoning at best.
Yes true. There is the option of ghcjs on the front end, so you can do both in Haskell. And ghcjs is very close to cbc. I think it even emulates the threading model.
Yeah, only if you are willing to spend anything (e.g. insanely large amounts of time) on it :(
Please correct me if I am wrong, but for any large project, Haskell actually adds more woes (e.g. laziness induced problems, no good debugging support) than the ones it addresses.
The Standard Chartered people had to invent a new language (mu) [1] which doesn't have laziness and the horrors associated with it.
BTW, you can get anything done even in (any Turing complete) assembly language too!
This is like saying that Java has "strictness induced problems". It's true, but probably disingenuous. Obviously large, well-funded strict object-oriented projects have memory leak problems as well (all browsers).
> no good debugging support
One generally doesn't require as much debugging support for Haskell, but it's actually quite nice if you follow a debugging process amenable to pure functional languages. People coming from a Java background want e.g. a breakpoint debugger, which doesn't really make any sense at all in a pure functional language; a vastly superior approach is to do e.g. quickcheck-style checking or input/output debugging on pure functions. If your code is impure, you can essentially debug like normal.
Bugs in Haskell also aren't the same as most of the bugs in other languages; you never get null pointers, for example. Every bug in Haskell is either a logic bug (which can often be debugged purely, and can be minimized by the careful application of types) or an atotality bug (which can be completely avoided by totality/completeness checking, and dynamic debugging of such bugs is getting much better with the new implicit callstack feature added to recent versions of GHC).
How can I be sure that some lazy code (may be from some library) may not encounter "head []" at all?
Of course, I can avoid that by avoiding all such libraries.
Another painful thing is the exception handling is also not as clean and clear as, say Java/Python exception handling, AFAIK.
Please correct me if I am wrong here, and I will be a happy camper. In fact, I love Haskell as it has taught me how to think clearly. But I am scary to use it in production, sorry for that.
It's actually quite easy. Enable the completeness checker. It won't let you use head, because it's incomplete. In other words, it will say "stop using head".
What this entails practically is something like a) using safe head, which has type [a] -> Maybe a, or b) using the non-empty list type, or c) using streams, which don't have an empty constructor. There are lots of things you can do, but the general approach is "use pattern matching to cover all cases". The compiler can tell you if you've done this or not, and it you do your program will never crash.
>Another painful thing is the exception handling is also not as clean and clear as, say Java/Python exception handling, AFAIK.
Monadic exception handling is 100x easier than in Java or Python. Java copied Haskell/ML's use of Maybe/Optional for avoiding null pointers in Java 8, but they haven't yet figured out Haskell's use of Either and friends for exception handling.
Handling true exceptions in Haskell outside of IO code is worse than in Java, which is probably what you're thinking of, but most code bases completely avoid it. It's not hard at all. Handling true exceptions in IO is often nicer than Java, because Haskell has well-thought-out primitives like bracket.
That does not warn about using `head`. It wouldn't even warn about an attempt to define `head`, so long as you do so with a call to `undefined` or `error` (which is effectively what's done in the base libraries).
You're right, I didn't realize that. Thankfully, `head` is one of the few common functions that's incomplete, and it's usually pretty obvious what they are.
> It wouldn't even warn about an attempt to define `head`, so long as you do so with a call to `undefined` or `error`
1. It's syntactically quite simple to avoid these two.
2. If you're using these, you're obviously aware your program can fail.
3. fdefer-typed-holes was introduced as a better alternative to undefined that warns you when used.
It's syntactically quite simple to avoid those two in your own code. You're not necessarily aware that a library you're using is using these.
That said, the community is pretty good at nudging people toward total functions, particularly in commonly used libraries (Prelude notwithstanding). And as you say, it helps that it is generally obvious when non-totality is newly introduced - infinite loops being the biggest exception, but that's unavoidable anywhere you don't have an actual totality checker.
To my mind, it differs importantly in that `head []` is something you basically can't inspect, and so you don't wind up passing it as something meaningful expecting the other side to check for it.
While I think this is an important difference, `head` is still harmful.
> Please correct me if I am wrong, but for any large project, Haskell actually adds more woes (e.g. laziness induced problems, no good debugging support) than the ones it addresses.
If you want to make a blanket assertion like that, then the onus is on you to provide some evidence of it. The fact that a strict dialect of Haskell exists somewhere in the world and is being used for application X is interesting, but it does not support your claim about Haskell's viability as a general-purpose language.
> The Standard Chartered people had to invent a new language (mu) [1] which doesn't have laziness and the horrors associated with it.
This is a terrible myth that needs to die. Mu is strict because it was designed to target a pre-existing strict runtime. Nothing at all to do with any perceived downsides of laziness, including space leaks.
Haskell has compile time problems when used in real project (tm) codebase scales and is hard to predict memory or cpu usage due to it's lazy nature sometimes.
I have no idea if elm is any better in that case, but both things make me scared to use it in production systems.
> But my understanding is that strictness for Elm was chosen mainly to overcome issues with FRP, which it's now abandoned
Laziness also requires you to ship a runtime, which is annoying on the web. Plus it's hard to debug performance problems, and you need more language complexity to allow you to opt-out of it. There are ways to opt-in to laziness in Elm via libraries, which seems to be becoming accepted as the right way to do things these days.
> But my understanding is that strictness for Elm was chosen mainly to overcome issues with FRP, which it's now abandoned
Laziness also requires you to ship a runtime, which is annoying on the web. Plus it's hard to debug performance problems, and you need more language complexity to allow you to opt-out of it. There are ways to opt-in to laziness in Elm via libraries, which seems to be becoming accepted as the right way to do things these days.
Elm seems to have a much stronger developer UX story than Haskell (just look at how much better its error messages are than ghc's), and the ability to share data models across the frontend-backend border would be awesome -- an end-to-end typechecked stack with easy sharing.
With Elm on the server too, you could easily implement server rendering to initialize the page for fast load times.
I wouldn't say it's understandable by all humans yet. I've had this experience where just when I think I'm grokking it, I hit a line of code that makes me cross-eyed and I can't find any traction at all and it's basically impossible to look up help. This is a combination of the maturity level of the project and also the documentation, but I get a distinctly not-quite-there-yet feeling with it (to be fair it is < 1.0). While elm has come a long way and has some great ideas, but I'm not 100% comfortable using it for something real yet.
I'm also not convinced by the cross-component communication / tree of components story yet. That still feels awkward to me. Not to turn this religious or anything, but tbh the static typing which feels like such a strength within a component, feels like it's in the way between components and results in some boilerplate, verbosity, and overly tight coupling. Really not trying to troll here -- I want to love it. YMMV.
> [static typing] feels like it's in the way between components and results in some boilerplate, verbosity, and overly tight coupling
Just curious, is this with regards to Elm / ML-style static typing specifically, or were you talking about it in combination with languages like C#/Java/etc?
I'm an elm noob, but I've been using F# for a good while, and its ML style of static typing is almost like the exact opposite experience of working with things like Java. Significantly less code, less boilerplate, and more expressive[0][1]. For example, one of the coolest features of F# that really showcase this, are type providers:
With them, you can leverage F#'s type system to automatically infer the structure and type of any external data source. Which means practically zero boilerplate or "ORMs" needed for things like reading-from/writing-to databases, making web api calls, parsing json/xml, or even interfacing with packages from entirely different languages like R [2].
So static typing can definitely have a lot of cool/practical benefits besides just catching bugs that make life easier, while still maintaining the flexible/lightweight feel of languages like python. However languages like C++ and Java have definitely seemed to have given it a bad name for a while, and haskell's whole tie-in with abstract math hasn't historically made it very accessible for us average programmers to notice all the tricks it has up its sleeve.
Elm is still young and I'm a total novice to it, but after working in F#, I'm definitely sold on it and like where it's going.
So here's the Elm high level on the tree of components:
An Elm component is typocally a Model type and a Msg type. When side effects occur, the component receives a call to update with the model and the message. It returns a new model and a new side effect to cause (could be none). The model is then rendered into a view.
If you have a user profile component then maybe you have a user info component and a settings component. And maybe the settings component has a notifications component and a privacy component.
The Model for that is pretty straightforward. It's just a tree of data.
The Msg for that is what is being complained about. Any side effects caused by a child component will call the update function of the parent. It then has to route that to the child component.
The result is that you have:
type Msg = ProfileMsg Profile.Msg | SettingsMsg Settings.Msg
type Profile.Msg = ...
type Settings.Msg = NotificationsMsg Notifications.Msg | PrivacyMsg Privacy.Msg
type Notifications.Msg = ...
type Privacy.Msg = ...
So now your top level msg could be a SettingsMsg (Settings.PrivacyMsg (Privacy.SetDefault Privacy.Self))
And in order to process it in update you have to unwrap the outer type (like SettingsMsg) and then call update on the child component with the data from the msg. You repeat until a component can handle it. The the component returns a new model and possible new side effect. You wrap up that side effect in something like SettingsMsg and return it along with your new model.
It's a lot of boilerplate. As far as creating coupling, what if you want to use the notification component elsewhere in the app. Now something other than Settings needs to wrap it so you get Settings.NotificationMsg and Toolbar.NotificationMsg.
Thank you for taking the time to clarify and explain. That's exactly what I was talking about.
Worth noting -- it might be that there's just a missing construct/approach itty bitty piece of language support here that would make this problem a lot smoother.
I'm actually surprised I've not heard of anyone else express something other than complete satisfaction about it as it doesn't take much messing around to whack into it.
I don't understand how one can understand Elm and not understand Haskell, unless the expectation that Haskell is difficult makes people's brains shut down without even trying.
Most of the ML-esque concepts that make Haskell "hard" to read if you come from a C/Python/Java/etc. background (ADTs and pattern matching, application by adjacency, etc.) are present in Elm as well.
> I vastly prefer Elm's record syntax to Haskell's,
Are you familiar with Lenses? Classy lenses in Haskell provide a slightly less sexy but more powerful system of structural typing.
Elm looks like a simplified and specially a rebranded Haskell, a "functional language for humans". This could work wonders as marketing strategy but there is still a remaining pain point blocking Elm aspiration to become mainstream: community management. There is plenty of room to improve there.
On another note, with Web Assembly coming, I think ELM could stand to benefit greatly from compiling to WA instead of JS...but that is perhaps just me.
> Otherwise, it will dwindle away soon into the endless annals of forgotten languages.
The opportunity I perceive for Elm to avoid this fate is Phoenix adopting it in the default new project, in a similar fashion to Rails adopting CoffeeScript.
Yes, perhaps to clarify: I mean why not have Elixir be the language that compiles to JS, rather than Elm. Then you only need one language for frontend and backend (in the context of a Phoenix app).
> But why would they use Elm instead of Elixir as the language?
The same reason Rails would use CS instead of Ruby -- its a lot less work to leverage an existing front-end language than to build a rock solid compile-to-JS option for your existing backend language.
This would be an easy way to make no one want to use Phoenix. Elm is just way too different and the truth is that while it's cool it's an ML so it's "weird" and most devs seem to be doing fine with just modern JavaScript. Having to either learn a new language or remove a plugin just to get something basic going would suck.
ES2015+ is the CoffeeScript of Phoenix.
And like moosingin3space says, Elm support is just a plugin away.
I didn't remember this being too bad. I just checked with Elm 0.17 using the tutorial's [1] nesting/3-gif-pair.elm as the main. Size is 209k out of elm-make, 60k minified (closure compiler advanced), and 19k gzipped. I wouldn't use it for validating a form field but the size seems completely reasonable for a language runtime.
It used to be huge (including the entire standard library for simple apps). Afaik though the generated code has been improved in the last update to be compatible with google's closure compiler and things like browserify or webpack that can greatly optimise the size of your code. Could be wrong though.
While I love Elm, after the recent release that replaced Signals, it's going to take a long time for me to bet anything with money on it. My toy app didn't have many dependencies, but when so much breaks on upgrading the runtime it's a hard sell.
(Not to disparage the change or the work behind it! I think it was the right call, and again, love the language and community. Just expressing, after the last experience, that I'll wait until 1.0 since the language is still undergoing drastic changes)
Isn't this basically the same strategy every challenger technology takes to replacing an incumbent one? The problem is your organization has to be willing to bet on Elm as a tool. What does the org do if you leave, get sick, or are terminated? In many ways choosing niche technologies with esoteric syntax or paradigms is like holding your organization hostage IMO.
Now does that mean nobody should ever choose a new language or other tool? No, but the cost of adoption needs to be evaluated. I use Kotlin where I work right now and I had to address the same questions initially. The argument for Kotlin was that it's not that different than Java and most good Java developers can pick it up easily OR Scala developers (though they might do that begrudgingly...).
I've never been a fan of doing front-end web programming because of my distaste for Javascript. Elm solved that problem for me. I like the syntax, type checking, and I've never had any code that passed the Elm compiler error out on me in production.
I also like the functional programming aspect of Elm, and the syntax is quite nice (similar to Haskell, only smaller and easier to learn).
By Elm you mean that language that changes all its core functionalities[1] every day? I've tried it some months ago, now when I was about to try it again in a new project, I discovered everything I had learn is useless.
The idea is really still the same, just the naming and structure changed a little bit. I'm not sure why he labeled it a farewell since the core concept is the same.
Either way, it's not like it changes every day - it just hasn't left beta yet. This change is definitely for the better, and its usually good to make big, beneficial changes as soon as possible rather than waiting for a 2.0 release.
86 comments
[ 4.7 ms ] story [ 162 ms ] threadThe Elm dev(s?) really need to fix the Architecture Tutorial and write a proper language handbook.
Right now, the bad docs are pretty off-putting to someone coming to the language.
It's a shame, really, because I think Elm is great.
I wish Evan allowed others to contribute to the official documentation. Right now Elm feels more like Evan's personal project than a project that is owned by the community.
Other then that, the community has done a good job of writing up documentation, and Richard Feldman is working on a proper book.
I'm really rooting for Elm, I so prefer it to TypeScript and alternatives.
Sadly, no time on my hands to get involved.
While elm-lang/navigation and evancz/url-parser get you 80% there, the remaining 20% cause a lot of pain.
I am very optimistic that in the coming months this situation is going to improve tremendously. If we all share more knowledge, tutorials, guides, the whole community will win!
http://www.gizra.com/content/faithful-elm-amazing-router/
I'll be back in another few months, hope the situation improves.
Also, I could totally make a case for Elm at work right now... if it had usable documentation.
I think the docs could use a chapter on functional programming and how that works in the land of ML languages, and perhaps a few walk through examples of some simple, but not overly simplistic, apps.
So far though I think the language is pretty interesting, but I've yet to do anything really fancy with it.
I would sum it up as:
-) a stripped down, simplified version of Haskell
-) with a good concept for side effects
-) that compiles to Javascript
-) gearded towards writing type safe frontend code for the Browser
-) strongly nudging you towards a clean, well architected app structure (see 'the Elm Architecture').
I think it's on the tipping point right now:
if enough people jump on board, the language get's good documentation, and the library ecosystem grows, I see a great future for Elm.
Otherwise, it will dwindle away soon into the endless annals of forgotten languages.
The one piece I'm really looking for is server-side Elm, though. I've love the ability to write both my client and my server in Elm. I know there are some projects to allow Elm via node.js but they're still quite rough.
(Is anyone looking into transpiling Elm to Standard ML, so that it can be compiled to fast native code with MLton? Because that'd be, like, really cool.)
https://news.ycombinator.com/item?id=11916096
Most of the other reasons boil down to Haskell not being Elm --- they work in different ways and solve problems differently. There's always going to be impedance mismatch between the two. (Do I solve this problem with monads or with state-mutation functions?) This is going to use up valuable problem-solving bandwidth which I'd rather spend making the project more awesome.
The question was about using haskell on the back end. Also, previous attempts at sharing client and server code in other langs are sophmoric at best. In reality, there will always be a boundary that requires differences in front end and back end code.
> Haskell is not Elm
Doesn't answer the question, circular reasoning at best.
A service isn't a client though. They work in different ways and solve problems differently
There's value in sharing code between client and server. It may not outway the costs, but there's definitely value in doing so.
Yeah, only if you are willing to spend anything (e.g. insanely large amounts of time) on it :(
Please correct me if I am wrong, but for any large project, Haskell actually adds more woes (e.g. laziness induced problems, no good debugging support) than the ones it addresses.
The Standard Chartered people had to invent a new language (mu) [1] which doesn't have laziness and the horrors associated with it.
BTW, you can get anything done even in (any Turing complete) assembly language too!
[1] http://anil.recoil.org/papers/2011-cufp-scribe-preprint.pdf
Edit: added the Standard Chartered example
This is like saying that Java has "strictness induced problems". It's true, but probably disingenuous. Obviously large, well-funded strict object-oriented projects have memory leak problems as well (all browsers).
> no good debugging support
One generally doesn't require as much debugging support for Haskell, but it's actually quite nice if you follow a debugging process amenable to pure functional languages. People coming from a Java background want e.g. a breakpoint debugger, which doesn't really make any sense at all in a pure functional language; a vastly superior approach is to do e.g. quickcheck-style checking or input/output debugging on pure functions. If your code is impure, you can essentially debug like normal.
Bugs in Haskell also aren't the same as most of the bugs in other languages; you never get null pointers, for example. Every bug in Haskell is either a logic bug (which can often be debugged purely, and can be minimized by the careful application of types) or an atotality bug (which can be completely avoided by totality/completeness checking, and dynamic debugging of such bugs is getting much better with the new implicit callstack feature added to recent versions of GHC).
To me, head [] is basically a null pointer.
Of course, I can avoid that by avoiding all such libraries.
Another painful thing is the exception handling is also not as clean and clear as, say Java/Python exception handling, AFAIK.
Please correct me if I am wrong here, and I will be a happy camper. In fact, I love Haskell as it has taught me how to think clearly. But I am scary to use it in production, sorry for that.
What this entails practically is something like a) using safe head, which has type [a] -> Maybe a, or b) using the non-empty list type, or c) using streams, which don't have an empty constructor. There are lots of things you can do, but the general approach is "use pattern matching to cover all cases". The compiler can tell you if you've done this or not, and it you do your program will never crash.
>Another painful thing is the exception handling is also not as clean and clear as, say Java/Python exception handling, AFAIK.
Monadic exception handling is 100x easier than in Java or Python. Java copied Haskell/ML's use of Maybe/Optional for avoiding null pointers in Java 8, but they haven't yet figured out Haskell's use of Either and friends for exception handling.
Handling true exceptions in Haskell outside of IO code is worse than in Java, which is probably what you're thinking of, but most code bases completely avoid it. It's not hard at all. Handling true exceptions in IO is often nicer than Java, because Haskell has well-thought-out primitives like bracket.
What's this "completeness checker"?
You're right, I didn't realize that. Thankfully, `head` is one of the few common functions that's incomplete, and it's usually pretty obvious what they are.
> It wouldn't even warn about an attempt to define `head`, so long as you do so with a call to `undefined` or `error`
1. It's syntactically quite simple to avoid these two.
2. If you're using these, you're obviously aware your program can fail.
3. fdefer-typed-holes was introduced as a better alternative to undefined that warns you when used.
That said, the community is pretty good at nudging people toward total functions, particularly in commonly used libraries (Prelude notwithstanding). And as you say, it helps that it is generally obvious when non-totality is newly introduced - infinite loops being the biggest exception, but that's unavoidable anywhere you don't have an actual totality checker.
While I think this is an important difference, `head` is still harmful.
If you want to make a blanket assertion like that, then the onus is on you to provide some evidence of it. The fact that a strict dialect of Haskell exists somewhere in the world and is being used for application X is interesting, but it does not support your claim about Haskell's viability as a general-purpose language.
This is a terrible myth that needs to die. Mu is strict because it was designed to target a pre-existing strict runtime. Nothing at all to do with any perceived downsides of laziness, including space leaks.
Most Haskell language extensions just save you some typing or give you some extra verification; they're almost never actually necessary.
I have no idea if elm is any better in that case, but both things make me scared to use it in production systems.
Laziness also requires you to ship a runtime, which is annoying on the web. Plus it's hard to debug performance problems, and you need more language complexity to allow you to opt-out of it. There are ways to opt-in to laziness in Elm via libraries, which seems to be becoming accepted as the right way to do things these days.
Laziness also requires you to ship a runtime, which is annoying on the web. Plus it's hard to debug performance problems, and you need more language complexity to allow you to opt-out of it. There are ways to opt-in to laziness in Elm via libraries, which seems to be becoming accepted as the right way to do things these days.
With Elm on the server too, you could easily implement server rendering to initialize the page for fast load times.
A famously good aspect of Elm is it's error messages. Very learner-friendly.
https://twitter.com/id_aa_carmack/status/735197548034412546
http://elm-lang.org/blog/compilers-as-assistants
http://elm-lang.org/blog/compiler-errors-for-humans
I'm also not convinced by the cross-component communication / tree of components story yet. That still feels awkward to me. Not to turn this religious or anything, but tbh the static typing which feels like such a strength within a component, feels like it's in the way between components and results in some boilerplate, verbosity, and overly tight coupling. Really not trying to troll here -- I want to love it. YMMV.
Just curious, is this with regards to Elm / ML-style static typing specifically, or were you talking about it in combination with languages like C#/Java/etc?
I'm an elm noob, but I've been using F# for a good while, and its ML style of static typing is almost like the exact opposite experience of working with things like Java. Significantly less code, less boilerplate, and more expressive[0][1]. For example, one of the coolest features of F# that really showcase this, are type providers:
https://channel9.msdn.com/Blogs/Seth-Juarez/Type-Providers-i...
With them, you can leverage F#'s type system to automatically infer the structure and type of any external data source. Which means practically zero boilerplate or "ORMs" needed for things like reading-from/writing-to databases, making web api calls, parsing json/xml, or even interfacing with packages from entirely different languages like R [2].
So static typing can definitely have a lot of cool/practical benefits besides just catching bugs that make life easier, while still maintaining the flexible/lightweight feel of languages like python. However languages like C++ and Java have definitely seemed to have given it a bad name for a while, and haskell's whole tie-in with abstract math hasn't historically made it very accessible for us average programmers to notice all the tricks it has up its sleeve.
Elm is still young and I'm a total novice to it, but after working in F#, I'm definitely sold on it and like where it's going.
[0] https://fsharpforfunandprofit.com/series/why-use-fsharp.html
[1] https://skillsmatter.com/skillscasts/4971-domain-driven-desi...
[2] https://www.youtube.com/watch?v=_BOST3W88-Y
An Elm component is typocally a Model type and a Msg type. When side effects occur, the component receives a call to update with the model and the message. It returns a new model and a new side effect to cause (could be none). The model is then rendered into a view.
If you have a user profile component then maybe you have a user info component and a settings component. And maybe the settings component has a notifications component and a privacy component.
The Model for that is pretty straightforward. It's just a tree of data.
The Msg for that is what is being complained about. Any side effects caused by a child component will call the update function of the parent. It then has to route that to the child component.
The result is that you have:
type Msg = ProfileMsg Profile.Msg | SettingsMsg Settings.Msg
type Profile.Msg = ...
type Settings.Msg = NotificationsMsg Notifications.Msg | PrivacyMsg Privacy.Msg
type Notifications.Msg = ...
type Privacy.Msg = ...
So now your top level msg could be a SettingsMsg (Settings.PrivacyMsg (Privacy.SetDefault Privacy.Self))
And in order to process it in update you have to unwrap the outer type (like SettingsMsg) and then call update on the child component with the data from the msg. You repeat until a component can handle it. The the component returns a new model and possible new side effect. You wrap up that side effect in something like SettingsMsg and return it along with your new model.
It's a lot of boilerplate. As far as creating coupling, what if you want to use the notification component elsewhere in the app. Now something other than Settings needs to wrap it so you get Settings.NotificationMsg and Toolbar.NotificationMsg.
It just gets clumsy.
Worth noting -- it might be that there's just a missing construct/approach itty bitty piece of language support here that would make this problem a lot smoother.
I'm actually surprised I've not heard of anyone else express something other than complete satisfaction about it as it doesn't take much messing around to whack into it.
Can you give an example? Can't think of anything off the top of my head that fits this description.
I don't understand how one can understand Elm and not understand Haskell, unless the expectation that Haskell is difficult makes people's brains shut down without even trying.
Most of the ML-esque concepts that make Haskell "hard" to read if you come from a C/Python/Java/etc. background (ADTs and pattern matching, application by adjacency, etc.) are present in Elm as well.
> I vastly prefer Elm's record syntax to Haskell's,
Are you familiar with Lenses? Classy lenses in Haskell provide a slightly less sexy but more powerful system of structural typing.
http://tech.noredink.com/post/126978281075/walkthrough-intro...
On another note, with Web Assembly coming, I think ELM could stand to benefit greatly from compiling to WA instead of JS...but that is perhaps just me.
http://elm-lang.org/blog/farewell-to-frp
The opportunity I perceive for Elm to avoid this fate is Phoenix adopting it in the default new project, in a similar fashion to Rails adopting CoffeeScript.
There is already at least a start at a Erlang Javascript parse transform: https://synrc.github.io/shen/
The same reason Rails would use CS instead of Ruby -- its a lot less work to leverage an existing front-end language than to build a rock solid compile-to-JS option for your existing backend language.
ES2015+ is the CoffeeScript of Phoenix.
And like moosingin3space says, Elm support is just a plugin away.
I bet Phoenix will not make a so heavy choice on frontend and keep the default to vanilla js.
[1] https://github.com/evancz/elm-architecture-tutorial
(Not to disparage the change or the work behind it! I think it was the right call, and again, love the language and community. Just expressing, after the last experience, that I'll wait until 1.0 since the language is still undergoing drastic changes)
Now does that mean nobody should ever choose a new language or other tool? No, but the cost of adoption needs to be evaluated. I use Kotlin where I work right now and I had to address the same questions initially. The argument for Kotlin was that it's not that different than Java and most good Java developers can pick it up easily OR Scala developers (though they might do that begrudgingly...).
I also like the functional programming aspect of Elm, and the syntax is quite nice (similar to Haskell, only smaller and easier to learn).
I found this site useful for getting started with Elm 0.17: https://www.gitbook.com/book/evancz/an-introduction-to-elm/d...
[1]: http://elm-lang.org/blog/farewell-to-frp
Either way, it's not like it changes every day - it just hasn't left beta yet. This change is definitely for the better, and its usually good to make big, beneficial changes as soon as possible rather than waiting for a 2.0 release.
PureScript has the notable advantages of generating mostly-readable JavaScript and working in node. [1]
[0] - http://www.purescript.org/ [1] – http://try.purescript.org/ – click "Show JS Output"
https://github.com/ethul/purescript-react-example/blob/maste...