How to use Elm at work
elm-lang.org
elm-lang.org
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.
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.
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.)
A famously good aspect of Elm is it's error messages. Very learner-friendly.
https://twitter.com/id_aa_carmack/status/735197548034412546
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.
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.
With Elm on the server too, you could easily implement server rendering to initialize the page for fast load times.
Most Haskell language extensions just save you some typing or give you some extra verification; they're almost never actually necessary.
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
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 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.
While I think this is an important difference, `head` is still harmful.
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.
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.
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.
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...
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.
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.
ES2015+ is the CoffeeScript of Phoenix.
And like moosingin3space says, Elm support is just a plugin away.
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.
I bet Phoenix will not make a so heavy choice on frontend and keep the default to vanilla js.
The 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.
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!
I'm really rooting for Elm, I so prefer it to TypeScript and alternatives.
Sadly, no time on my hands to get involved.
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'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.
(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...).
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...
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.
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...