Hacker News new | past | comments | ask | show | jobs | submit login
A Farewell to FRP (elm-lang.org)
771 points by sharksandwich on May 10, 2016 | hide | past | favorite | 241 comments



I moved from React/Redux/Typescript to Elm a few months ago, and I'm now on my second serious project with it, making mobile application with Cordova. I've found it an absolute pleasure to use, and I especially like that you can be pragmatic about it; if there is something that is annoying to do in Elm then you can simply drop into Javascript/Typescript using ports.

Coming from languages like Actionscript/Javascript/Typescript/PHP I have found the whole Elm experience quite mindblowing; if it compiles, then it just seems to work. I hardly ever find myself poring over bits of code trying to debug a subtle error, and if I do the problem is going to be in the Javascript/Typescript bit.

Basically, I'm sold :)


> if it compiles, then it just seems to work

That's exactly been my experience with Elm.

For example, on a web project I had been working on I decided to add the 'search' feature; the very first change[1] actually worked! This is generally not possible with JavaScript.

[1] https://github.com/srid/chronicle/commit/4a6c18147bf1596b234...


Whenever I write a bunch of code that works right away I'm highly suspicious that I'm missing something.


>> if it compiles, then it just seems to work

This. I spent the first 14 years of my career in statically typed languages and only this year began working professionally on a Rails app... I really miss the compiler.


Rust has some really good compile-time checking, it really makes you express everything in a completely non-ambiguous way.

C++ on the other hand compiles stuff that may or may not work at all, it doesn't care, which can lead to all sorts of undefined behaviour down the road.

Compilers are not all created equal.


Huh. I find that when my C++ compiles, it almost always works. Correctly.

But I used the language for nearly 20 years, so maybe it's experience and the patterns I've learned?

Not that Rust or Elm aren't better options; don't know, really. Despite feeling like I'm an expert in C++, I don't actually like the language much. I've used Go some, and I like it, but I haven't tried Rust or Elm yet.


Well, I find that when my C++ compiles <segmentation fault>

When I first learned Java, still in my undergrad, my first impression (and nearly everybody's) was that when it compiles it works. It was still more work than Perl, Lisp, Prolog, and everything, but didn't require the annoying C debugging cycle.

But, anyway, all that is kids play near Haskell.


Hello! I don't know if English is your first language or not, but that last sentence was significantly confusing that I wanted to correct it for you and others who may read it.

The two idioms are 'child's play' & 'next to'. The words are correct synonyms but the usage is unusual enough that I read as having a totally different meaning my first time.


I was also confused by it. However I read the last sentence as the author making a meta-point by using purposefully incorrect grammar, a sort of reversal of the first sentence about c++ code compiling but leading to segfault--like an artistic statement. If it was an accident, then all the better!


:)

English is not my first language, and it is a rare construct. I thought it was correct.

Out of curiosity, how should it read?


I believe the common form is "X is child's play (next to|compared to) Y".


Don't worry too much, I always enjoy little gotcha's like this. It's like your brain has to think twice to understand the meaning, but in the end it does. It's really fun and colourful to read half modified phrases and that's how language evolves.


>didn't require the annoying C debugging cycle

Are we talking C or C++ ? C compiler is basically useless for compile time error checking because C type system is ridiculously weak. C++ on the other hand can buy you a lot of things with templates, richer type semantics, etc.

And also keep in mind that C++11 and onward is very different from C++ of yore and it catches a lot of errors at the compile time - move semantics and RAII really buy you a lot - the downside is that it's opt-in so the compiler won't force you - and it's less strict than say Rust, but it still gets you there 90% of the way.


Both languages have approximately the same problems for debugging. Explicit memory references are hard to follow, lack of overflowing protection requires a lot of extra caution to catch the errors, and failures lead to an unforgiving stop with at most a core dump. C++ is much better for statically catching errors, but templates and copy/move semantics make it even harder to debug.

And yes, I imagine C++11 is much better. Unfortunately, I didn't write anything big in C++ since then.


You avoid explicit references in C++11 and use STL containers which check for overflow.

I agree that C++ can have the same issues but the frequency is not comparable because you don't drop to those unsafe parts if you don't have to.

So with C++14 I get that "if it compiles it runs" feeling comparable to say C#.


You really owe it to yourself to give Rust a shot. A lot of things that you've encoded in convention(as any good C++ programmer should) are right there at the language level.

Ownership? You get an awesome sliding scale of Borrow Checker <-> Boxed <-> Rc/Arc

Mutation? Covered in Copy+Clone/Cell <-> &/&mut <-> RefCell

Thread Safety? Sync + Send guarantee that things which need to stay on a specific thread cannot be shared.

Combine that with Sum Types, Pattern Matching and much stronger functional constructs makes for a very compelling language.


Rust does sound interesting, but it doesn't seem to be focused on the areas that I need right now.

Go has GoRoutines, which are light threads; they can be executed on multiple CPU threads, but by default Go only allocates one CPU thread per physical CPU, even if you allocate tens of thousands of GoRoutines.

For the kind of networking server code I'm writing, light threading is far more efficient than using an OS thread per connection. 25-50x faster at higher server loads.

That's why I've ignored Rust to date; if Rust has light threading built in, but no one is talking about it (haven't found anything but real threads in my quick Google searches), then I'll take a look. Otherwise it will need to wait for me to have a task that Rust would be good for, and I'll stick with Go and TypeScript for the problems I'm solving right now.


Ah, sounds like Erlang/Elixir would be a better fit since the BEAM is the king of lightweight threads/processes.

You said C++ so that's why I suggested Rust, generally a GC tends to preclude spaces where C++ excels which is why I would think you'd want to try something other than Go.

On the Rust side there's things like mio for fast io but coroutine/light threads aren't really a focus afaik. I would still think you could get solid performance (and much better memory use, see Dropbox's replacement of Go) with an event based Rust system although that's not really my area of expertise :).


I am sure that a Rust team member will be here soon to set the record straight, however, my take:

> Rust side there's things like mio for fast io but coroutine/light threads aren't really a focus afaik

IO and concurrency/parallelism models are a very difficult topic to really discuss and quantify performance around.

The highest-known-performance network server architecture revolves around edge-triggered epoll/kqueue (evented, async IO) and state machines (eschewing the stack entirely.)

pthreads (speaking exclusively about POSIX here - Windows threads are far heavier-weight than pthreads) suffer the cost of context switching due to large (by default - this can be configured) stack sizes.

This is one reason why languages like Go and Erlang have their own stack and lightweight process (greenthread) implementations.

For the record: Rust had green threading, and I believe it was removed due to the overhead relating to supporting it. The simple fact that you really cannot control or know when FFI calls will block (libc included) or not makes greenthreading tricky.

The trickier thing, IMO, relating to async IO is just the compatibility aspect:

- Golang/Erlang control compatibility by offering entire ecosystems built around their greenthread models.

  - Golang even goes as far as replacing the vast majority of libc and much of what you would want to call out to C for.
- Rust, being a systems language, cannot dictate "all code must use async IO and this specific reactor/event loop implementation," the stdlib is too small (by design), calls to libc are too pervasive.

With all of that being said:

- I personally believe Rust core should adopt a blessed async IO system (event loop, OS-level abstraction layers, basically mio) that all code could opt into using. - Additionally, it would be lovely if, on top of said system, compiler support for stackless coroutines (a la async/await) and a multithreaded reactor were implemented.

I love Rust, but I can't use it for network server related tasks until this part of the ecosystem is more developed and made more consistent.

mio is the de facto stdlib AIO implementation, but there's still a lot of fragmentation, and many libs still use the blocking networking builtins, rendering them incompatible.


I've been reading about Elixir recently, yes. Thanks for mentioning it, though. I'll have to look at it at some point, but since my code is primarily run-in-a-browser, I'm currently stuck with compile-to-JavaScript languages. I'm concerned that Elixir is too functional for my tastes (I find Haskell to be too pure (and slow) to be really usable for most tasks I work on, for instance), but I will give it a look at some point.

The entire point of writing in Go or Elixir would be to avoid needing to write an event based system in Rust (or C). Writing code as if it's imperative but getting the speed of an event-based system is what I'm looking for. Event-based systems are notoriously hard to reason about and debug.


You just can't be happy if someone else is using Go, can you.


The parent is already experienced in Go and expressed interests in other languages, excuse me for indulging them :).


> But I used the language for nearly 20 years, so maybe it's experience and the patterns I've learned?

It definitely is. This is not the usual C++ experience. You are probably sidestepping all sorts of undefined behavior due to experience alone.


This matches my experience with C++. My code has improved hugely in simplicity and robustness as I've learned which C++ features are productive and which are just minefields.


> Huh. I find that when my C++ compiles, it almost always works. Correctly. > > But I used the language for nearly 20 years, so maybe it's experience and the patterns I've learned?

By contrast, I learnt OCaml and Haskell 2 weeks ago, and when my code in those languages compiles, it always works. I expect I'll have the same experience with Rust.


Funny. I managed to get Haskell to crash within about 20 minutes of first trying it out.

OCaml is supposed to be pretty fast, but so far Haskell hasn't impressed me with performance either.


What code did you write?


I wrote some code that iteratively would have just taken a while to run, but because Haskell wasn't using true tail recursion, it ran out of stack space.

I also read a paper that talked about extensive research into optimizing a convolutional network algorithm in Haskell, if I remember correctly. The algorithm even used mutable data structures for speed (because of course you need data to be mutable for speed). Roughly speaking, if you ran it on 16 CPUs, it was only 4x slower than the C algorithm running on one CPU. And Amdahl's Law [1] (as well as the graph in the article) hints that it may never actually be faster than the single CPU C version, no matter how many CPUs you split it onto, because of the overhead of sending the data around.

When people claim "immutability makes it easier to run on more threads, which is the future of optimization!" I just want to cringe. Immutability kills most performance enhancements you can possibly make on nontrivial code, even considering a single thread, having all your data be immutable does nothing at all to improve threading, and forcing all data transferred to another thread to be immutable kills a whole category of optimization.

When dealing with large amounts of data, you save tons of time by not copying it around.

/rant

Sorry. I've been listening to too many people talk about Haskell like it's an amazing silver bullet that will solve all of our problems. But There Is No Silver Bullet. Really.

[1] https://en.wikipedia.org/wiki/Amdahl's_law


Well, FWIW worth that's not the primary reason I like those languages. It's the safety.

After some experience with immutable data structures, you know how to make them efficient. For example most of the time you don't need to copy that much data - if you need to change a small part of a large data structure, you arrange it so you can re-use (re-point to) the parts you didn't change. On average you should be able to reduce your cost down to O(log(n)) which usually is "good enough".

That is the correct trade-off IMO - have a newbie start off writing safe code, that gets quicker and less memory intensive with experience. Not start off be blazing quick but unsafe, then add the safety with experience.

Did you know Rust (which defaults to immutable) is currently head-to-head with C in Debian's "fastest languages" comparison?

https://benchmarksgame.alioth.debian.org/u64q/rust.html


Haskell is beautiful - including the syntax and typesystem, but the performance claims made for it are ridiculous.

I switched to Ocaml to avoid the un-evalauted thunk and space complexity overhead.

Ocaml also doesn't compete with well written C or C++, but it's a lot more performant than Haskell for general purpose code.


Something like `main = head []` probably, lol.


It is a bug in the compiler. (Old joke).


I thought it was a bug in the specification? (Older joke.)


I have a marvelous proof that this bug does not exist, but the heap is too small to contain it.


The new C++ Core Guidelines & Guidelines Support Library and related tools are interesting efforts to specifically solve those problems.


If the issue is that "C++ compiles stuff that may or may not work at all" then I don't see how those guidelines will help the situation. A C++ project may or may not follow those guidelines and then we're back where we started.


My understanding is that the tools are the answer - it's a linter that must be run before landing/merging. See https://youtu.be/hEx5DNLWGgA for a demo of such tools.


Tools are just band-aids over an unsafe type system, and they are all too easy to ignore or never use them in the first place.


It depends on the community. See gofmt & gometalinter in the golang community.


Give it another year and the new batch of hotshot developers will reinvent static typing and perhaps one or two other features from the 1970s, but it'll have some cool name and only implement 50% of the functionality.


Modern static typing isn't remotely related to typing from the "1970's"


Well, depends on what you mean with modern static typing. In some ways, mainstream programming is finally catching up with ML, which is from the 1970s.

If you mean cutting edge PL research it's a different story of course.



The type systems in modern languages like Swift, Rust, Scala, Haskell, and even Kotlin go way beyond classical Hindley-Milner. Classical Hindley-Milner gives you parametric polymorphism over algebraic data types, along with an inference algorithm. No subtyping, no casts, no coercions, no overloading, no polymorphic literals, no interfaces. You basically get SML.

Consider that in 2006, MPTCs with fundeps was the preferred way to represent "a collection of items that can be compared via equality" [1]. Associated types were a vague research idea [2] that showed a lot of promise, but hadn't been implemented in any language with type inference (they did exist in C++ templates, but C++ isn't exactly what people think of when you say "modern type system"). Now both Rust and Swift feature polished implementations of associated types and use them pervasively in the standard library.

[1] https://en.wikibooks.org/wiki/Haskell/Advanced_type_classes#...

[2] https://prime.haskell.org/wiki/AssociatedTypes


> You basically get SML.

SML is still more usable than the statically type languages in use the most today (C++ and Java).


Yes, but by "modern static typing" I think we're talking about the latest generation of languages that have come out since 2010 (Swift, Rust, Kotlin, etc.)


"This will be the sixth time we have reinvented basic programming, and we have become exceedingly efficient at it."


What is that a reference to?


The Architect's big speech in The Matrix Reloaded, where he's talking about the machines tearing down and restarting the Matrix. "But, rest assured, this will be the sixth time we have destroyed it, and we have become exceedingly efficient at it." It was from memory and so a bit munged, though.


You might be interested in the Crystal language. It's a statically-typed, Object-oriented, Ruby inspired language. It's Ruby with types, basically.

You might also be interested in Elixir which ties in to the Erlang ecosystem, but if you are super into OOP (like me) you might find it slightly more difficult, but since you have experience with static-types, you probably know some FP stuff, and so it's not that bad.

Either way, best of luck. It takes a brave soul to fight with Rails. I've been writing Ruby for about three years now and still haven't touched Rails just because I can imagine how little fun it is to try and debug dynamic-typed web stuff. Noooooo thanks.


It's odd how people are in their perspectives on static vs dynamic. I can't for the life of me understand how people tolerate static typing on the web. Every time I've tried it the experience has been so tedious.

I just figure, everything is coming in as a string no matter what. It's going back out as a string. The only place it needs to be anything other than a string is something interesting is being done with it and since dynamic typing lets you just worry about it in those cases, it removes a lot of unnecessary code.

On the flip side, outside of web work i can't imagine the reverse.


> I just figure, everything is coming in as a string no matter what. It's going back out as a string.

Maybe so, but that only accurately describes things at the boundaries of your system. Your database tables still have columns that hold integers, dates, or floats. Sure, you could do the type coercions as needed, but at that point you're missing out on the valuable opportunity to validate your data as it enters the system. You can provide meaningful errors to users as early as possible, you can avoid defensive checks nearly everywhere else within your code, and you can just generally trust that invariants about your data are going to hold throughout the rest of your program.

This leads to smaller test suites, more concise codebases, and higher security assurances overall. If you look at the sorts of vulnerabilities that often pop up in Rails for example, many of them simply don't affect you if you use something like Virtus [0] to validate the types of your data as it enters the system.

I don't do much web development, but statically typed web development is the only way I've ever been able to tolerate it.

[0] https://github.com/solnic/virtus


You can avoid defensive checks anyway. Just don't writre them! /s


You know what else takes in strings and spits out strings? A compiler!

Here are a couple of other under-appreciated facts about compilers:

1. For regular grammars, they are easy to build with any kind of programming language.

2. For regular grammars, they are really really easy to build with statically-typed programming languages.

Now days, my web development is essentially just compiler construction for regular languages, and it just so happens that extremely statically-typed like the MLs (F#, in my case) are damn good for writing compilers (one joke is that it’s the only thing they’re good for). I write far fewer lines of code per feature than I ever did with ”dynamically“ typed languages like PHP, and it’s usually right the first time.


You build your system as a box that takes strings in and sends strings out. You then have to do a bunch of checks (as part of your de/serializing) at the boundaries only. Inside the box, all your logic and transformations are type safe, and indeed you can turn some logic issues into mechanically checked type-level issues, which are basically free unit tests.


I like this for lightweight applications. I imagine it could become a bottleneck for anything moderately heavyweight when it comes to data processing. Most web apps are designed to not do any heavyweight lifting on the client side, so it is a nice general paradigm for that.


Why a bottleneck? Static types don't have to add any runtime overhead. In fact, the type information isn't present at runtime at all in some languages. It's a compile-time guarantee that actually allows you to remove some runtime checks and assertions. And I think all bechmarks show that static languages are as a rule faster than dynamic languages.

If you're comparing two different designs in a statically language where one involves making lots of new types and the other just shuffles strings back and forth, then I can't say and it'd depend on the specific case. Generally, helping the compiler is a good thing, and obviously things like switching on an enumeration is much faster than a long line of string comparisons. Actually, strings are just a horrible datatype, so unconstrained and inefficient. Use strings less!


What typed languages have you used and what aspects do you find tedious? I find that the experience of writing brittle type-checking logic and tests in dynamic languages is rather tedious in its own right.


I find that even the typing experience is faster with static types, since we get better autocompletion/intellisense and there is no need to lookup documentation or other code all the time.


> I just figure, everything is coming in as a string no matter what. It's going back out as a string.

And everything in memory is a sequence of bytes. I don't see the relevance of this line of reasoning. I guarantee that whatever experience you've had with statically typed languages on the web, it's not a good language. Interfacing with dynamic systems is simply a matter of good abstractions, which many languages simply lack.

Take a look at F#'s type providers to see where you can go with this.


Yes everything is a string on the web, but IMO it's not the primitive data types that I'm concerned about so much - it's about the data structure (classes / interfaces). If I refer to my item's description property as `item.descripition`, statically typed language will scream that I have mistyped the property name before letting me run that code or, God forbid, releasing it.


> I have found the whole Elm experience quite mindblowing; if it compiles, then it just seems to work.

My mindblowing experience was facilitated by referential transparency where I had a page of code that became half a page after extracting some functions and restructuring the code and then have that half page collapse into several lines of boring code because I realized that the functionality can be re-expressed in terms of standard functions.

It is amazing to be able to think about an entire branch of code in isolation and be able to understand it in its entirety.


Care to share more about that? It would be really helpful for people looking at the language to see your progression. Could be something as simple as a gist with the code in your different stages.


I tried to look through the commits of that project but could not find something that captures this. Maybe it happened between commits.

Maybe I'm remembering it wrong. Maybe my mind exaggerated the memory. It happened last year while I was implementing Challenge No. 5:

https://github.com/pdamoc/elmChallenges


"if it compiles, then it just seems to work" Man, now that is tempting. Also, how easy are the ports? In ClojureScript you can use JavaScript pretty directly, but I often got a bit hung up translating the syntax (it's not that hard, it was just me).


I've never used ClojureScript so I can't speak for that, but the ports are now a lot easier in 0.17 as an outgoing port is simply a function that you can call, instead of messing about with Signals. Effectively, you send stuff to Javascript by calling the port function with a Javascript compatible value, and then you subscribe to messages on the way back in, which end up triggering a message on the update function of whatever component sent it out in the first place.

TL;DR its pretty easy once you've done it a few times


Ports are essentially event emitters. You can expose them from elm, and in your JS code you attach event handlers to them using .onMessage (I think, been a while).

You can post and receive messages from ports (depending on type). Type checking is done at runtime to make sure nothing breaks.

Cljs interop is easier (can just call a function directly).


Apparently a human-readable homoiconic language is still an unsolved problem...

In 0.17, commands and subscriptions mean that, not matter how deep you nest components, you can still send and receive messages to/from the outside world (i.e. ports).


Thank you for this endorsement. I am learning Elm, I like it a lot so far, but there are times where I question if this is really all necessary.

So first person experiences like yours help me continue and understand where I can be if I continue on the path I am.

Also, I would like to add that I really liked Signals and felt that they are good abstraction, but looking at Subscriptions and they also on surface level make sense.


Did I read correctly that you are using Elm with Cordova?

Perhaps you are using Elm to compile to HTML / CSS / JS which Cordova compiles to native code?


I came across it researching time travelling debuggers to implement in my flux implementation for android.

My mind was blown but never really got enough time to study it since it was low on my priority list.

I think you just pushed it to #2!


I am happy to see Elm evolving and it looks like a good framework, but there is a tendency in FRP articles to ignore prior work, as acknowledged at the end of the article:

> Note: Interested readers may find Lucid Synchrone interesting. Unfortunately for me, I had no idea my thesis had so much in common with synchronous programming languages at the time, but the connections are quite striking. I might argue that Elm was never about FRP.

My thesis was related to synchronous programming languages and articles about FRP tend to have too little to say about them, for my taste. Yes, there is a word or two in the related work, but also it looks like some wheels are being reinvented.

The subscriptions model reminds me of Esterel, which is imperative and uses await/emit pairs. In the domain of GUIs, which is related to Elm, there is ReactiveML (see "ReactiveML, Ten Years Later" (https://www.di.ens.fr/~pouzet/bib/ppdp15.pdf)). Look also at Lustre or Signal, with Signal allowing directives to define multiple execution units: this is used to generate concurrent programs exchanging values with message passing.

The domain is different, though. Synchronous languages do not target web interfaces. They are about embedded systems and as such, they are mostly static. On the other hand, they are compilable into a simple event loop with static memory usage and constant execution time. Maybe some of the existing research could be useful to something like Elm, even if it does not target the same problems.


I was interested in the synchronous languages but never got around to reading more in depth about them. Can you recommend a book on the subject?

The two languages I was most interested in were Lustre and Esterel.


Synchronous Programming of Reactive Systems, Halbwachs

Synchronous Languages for Hardware and Software Reactive Systems, Berry

Designing Embedded Systems with the SIGNAL Programming Language, Gamatié

The Synchronous Languages 12 Years Later (http://www-verimag.imag.fr/~halbwach/PS/iee03.pdf)

There are some resources at Verimag (http://www-verimag.imag.fr/Tempo,32.html?lang=en) and the Esterel website (https://www-sop.inria.fr/meije/esterel/esterel-eng.html). You can search the HAL database too (hal.inria.fr) and maybe have a look at SCADE (http://www.esterel-technologies.com/products/scade-suite/).


I'm a huge INRIA fan so I decided to play with Esterel a while back. If people call Haskell an 'academic' language, I have no idea how an average person would describe Esterel. "Thinking in" Esterel is going to be a huge shift for the traditionally trained CS guy who's never touched a circuit. Half the people in our field didn't even go to go to school for CS[1]. Hell, I've got a decent amount of LabVIEW and Verilog experience, and even I have trouble with it.

That being said, it's interesting and those resources are definitely going on the Kindle. Do you have a link to your thesis ? (Judging by your comment history, it has a high likelihood of being quality).

[1] Not to denigrate those who were less traditionally educated. The brightest engineer I know is a high-school drop-out. They however were motivated enough to read Sipser, Gunter, B Peirce, and all the standard texts (again, not as a requirement to read All The Fancy Books, but just to enrich his own mind for the sake of knowledge - without that curiosity, one might have a difficult time being more than a code-monkey (not that there's anything wrong with that, but I personally have the scratch of "how does this work" that I need to keep on itching compulsively)).


> Do you have a link to your thesis?

There is only a French version:

https://tel.archives-ouvertes.fr/tel-00680308/

The context is about using a constraint programming approach (in Prolog) to model Lustre/Scade programs and automatically generate traces of input/outputs that satisfy a given test objective. With the help of my advisers I extended the GATeL tool to introduce what is known as "clocks" in Lustre and integrate them with other constraint domains to prune the search space efficiently.


I get the impression that synchronous programming is somehow only really known inside the French PL community, is that correct?


Synchronous programming is mostly a French thing but as far as I know there is also Quartz in Germany (https://es.cs.uni-kl.de/publications/datarsg/Schn09.pdf), Ptolemy in Berkeley (http://ptolemy.eecs.berkeley.edu/publications/papers/01/sr/s...) and some work at Virginia Tech (https://theses.lib.vt.edu/theses/available/etd-08112011-1613...).


Check out http://www.ceu-lang.org/

Then you can try it yourself.


> My thesis was related to synchronous programming languages and articles about FRP tend to have too little to say about them, for my taste.

What would you expect them to say exactly? Synchronous languages are first-order reactive programming, but FRP is about higher-order reactive programming.


As someone who is just getting started with frontend development, I decided to go with Elm instead of learning JS and React. I found the whole experience very pleasant, even as a beginner.

Not only is the elm code I write reliable, but I've found that adding more features does not bloat my code. Refactoring a codebase as it grows in elm is pleasant, and following the Elm Architecture guides me on the correct structure for the app.

Over the weekend I made a small site to show all Elm conference videos in one place. If you want to play around with 0.17 this project is just a bit above a "Hello World" example. Send a PR! https://elmvids.groob.io/


Bold move, but a good one, I think. I've been considering starting my students (just friends I mentor) on Elm for a while, but it's only this year I've heard of local companies hiring for Elm here in Salt Lake City.


I recently moved out to SLC area, shoot me an email aquiva at Google's mail.


Nice to read.

Last time I tried Elm, (1 or 1 1/2 years ago) tutorials and docs were kinda outdated. Got errors in this REPL thing they got for beginners on the webpage and nothing from the examples worked :\


I came back to it recently after a year and a half long break and it has improved dramatically. It's starting to feel like something I'd be comfortable using in production.


It is still pre-1.0 and the most recent release changed a lot, so I'd guess there is still opportunity for breakage in the future. But it's hopefully closer now.


What resources are you using to learn Elm?


I used https://pragmaticstudio.com/elm to get me started.


There's also a lot of similarity with Rx.JS and observable based (aka "Reactor") patterns:

    Rx.Observable.fromTime().subscribe(tick)

    Rx.Observable.fromSocket(mySocket).subscribe(handleEvent)
https://github.com/Reactive-Extensions/RxJS

Regardless of the exact library or pattern, the broader concept of treating data sources as asynchronous event streams you can subscribe and react to definitely simplifies data flow and makes systems very robust.

An additional benefit of this pattern is the natural way it makes it easy to filter, chain, map, etc onto these subscriptions. Once again from the Rx world, http://rxmarbles.com/ does a great job visualizing these patterns.


Exactly. Rx was created by MS research for Azure -- mostly to abstract away the threading model in the cloud - why reinvent the wheel when Observable / Rx is built for every platform you use and is fantastic.

When ELM came along with its signals, im like, meh, why not Rx? Im not even going to bother to learn it, your at v0.1 and ur gonna see why u need it soon enough. Subcritiption? Dont reinvent the wheel like Redux? Why not Rx? A few months later, everyone is going "how we we handle async actions properly?" Well thats an Observable my dear friend!

Just like when Flux "came out". They just rebranded Event Sourcing in the client UI.

Im getting pretty fed up with all this mumbo jumbo. I write C# mostly, i like FRP, ES, unidirectional flows. Im going to bring a slim universal c# solution with a typescript/JS bridge to the OSS community. The main philosphy is, one client/server architecture, to build scable responsive apps. With builtin backpressure handling.

If ppl had just embraced Rx like 6years ago when it was first V1'd, imagine how much further along the road we would be now? Like seriously, get over urself OSS fanboys, just cause its MS, doesnt mean its bad.


/agree.


I think that's my biggest question reading the article here: Has Elm been ignoring the work going on with Rx all this time?

These Elm subscriptions sound like "half" of Rx, and from what I can is still 'missing' thus far some of the "higher order" Observable tools such as filter, chain, map, throttle, et al.


Definitely not ignoring. I talk about the relation between Elm and that sort of stuff in https://youtu.be/Agu6jipKfYw Lots of things look similar in this area that are not.

I also offer an analysis of "higher order" observables in https://youtu.be/DfLvDFxcAIA, and the big difference is the underlying thread architecture you get using these two.

I hope I'll be able to make these sorts of things clearer in time!


After reading the article, I went into their IRC chan to post this question (i.e. are they leveraging all the research from really-smart(TM) PhD's at Microsoft Research & production testing that Rx has behind it). This guy has a doctorate, so I'd imagine there was a reason why RxJS wasn't leveraged, especially since it seems like a natural fit especially with Typed.*. And n general the Elm/Haskell community is way less fan-boi-trendy-node-js-macbooks-Rails-flavor-of-the-wheel guys who will nay-nay anything that is Microsoft.

I'd love to make the Elm jump, but it still has the Haskell stigma (not enough engineers making hiring difficult, too 'academic', etc) where my clients (enterprise) won't let me dev with it. They do however let F# in some projects. MS should do what they did for OCaml -> F#, but for Elm -> something_I_can_say_is_first_party_MS_supported.


> And n general the Elm/Haskell community is way less fan-boi-trendy-node-js-macbooks-Rails-flavor-of-the-wheel guys who will nay-nay anything that is Microsoft.

This really hasn't been the case for RxJS at all. It's been praised and version 5 is largely a community effort rather than just an MS effort. You got Ben Lesh and Andre Staltz putting in the most work and neither are MS.

The only thing from MS people don't seem to give a chance is .NET. Everything recent (VS Code, open sourcing stuff, Chakra engine, etc) has been met positively and not dismissed.


I feel some of this.

I almost had a Microsoft-first shop let me use Haskell when I pointed out how many of Haskell's lead developers worked at Microsoft Research UK.

As for the Microsoft "first party" F# equivalent for the web, that would be Typescript. Typescript's typing isn't yet to the rigor of OCaml, much less Haskell or Elm, but it's getting better every release.


I learnt Haskell at uni in 2000. Now im a c# guy mostly unless im in the broswer. You know u can program in pretty much the same way using C# as u can haskell? I dont see the attraction of going to F#, but thats because i need to consider maintaince costs of the code-base as well as them both compiling down to IL.

Functional langauges are great, dont get me wrong, if i had the choice id probably give 'elixir' a 'rust' ;) but i make do with my existing c# knowledge, sprinkle in some Rx, isolate my side-effects in closures when pure functions cant be had, and im pretty happy with both the look, readability and maintance burden my code generates. The advantage of C# here over a first order functional lanuage is my ability to customise the syntax to make things self-documenting as well.


This looks very cool.

In ClojureScript, we have the re-frame pattern/framework, which is built on Reagent, which is a ClojureScript wrapper of React.

re-frame is all about subscriptions, using a "big atom" to hold application state client-side. Seeing Elm implement the same subscription pattern makes it look pretty tempting.

My understanding is that ClojureScript and Elm have some similarities - functional, pleasant to work with - with one significant difference being that Elm is typed.


Elm is typed, Clojurescript is homoiconic. 2 great features.

Wondering if you could make a lisp where `lambda` or `fn` required type annotations, such as

    (defn add 
      [int -> int -> int] ;; type annotation
      [x y] ;; arguments list
      (+ x y))
Then it would be homoiconic - something that has saved me hundreds of lines of code (and the less code, the less bugs as a rule of thumb).

Then every function down to the very basic lisp functions would have types. Dunno how doable this is - but it doesnt matter. Someone implemented it in Common Lisp in the 80s I'm sure.


There's Typed Racket [1] and for Clojure there's core.typed [2]which do pretty much that. For Clojure there's also Schema [3], which is a bit lighter weight (it's not a full type system), but still gets you some of the benefits like validation and documentation.

[1] https://docs.racket-lang.org/ts-guide/ [2] https://github.com/clojure/core.typed [3] https://github.com/plumatic/schema


Neither fit the bill though - because not every function ever written in the language is annotated. To be nice to use, it should be an all-or-nothing affair.

I say this as a huge clojure fan - my clojure programs with dynamic types work great. I rely on predicates (functions ending in -?) in I/O, otherwise I'm sure things work.


Why is annotation important? I agree it needs to be possible, but ultimately I want to push the majority off into inference, and only explicitly annotate when necessary or formalizing interfaces OCaml-style.

Though I sure do wish I could have lisp (or clojure, specifically) syntax in OCaml-land.


How about Shen [1]?

A Lisp with types, built-in Prolog, optional lazy evaluation and more. It scratches my Lisp/Haskell love affair.

[1] http://shenlanguage.org/


This is why (ignoring the batshit syntax) I'm quite fascinated by urbit's language hoon, since it handles type signatures by evaluating the function with type objects rather than straight arguments, so the above without the annotation would already be strongly typed and valid across anything that supported +


There's Typed Racket and Clojure's Core.Typed. In Common Lisp you can `declaim`/`declare` attributes to functions and values, and many implementations allow `declaim`-ing types. It's also common for them to propagate and check type assertions at compile-time e.g.

    (defun foo (bar)
      (if (numberp bar)
        (car bar)
      x))
should error out in SBCL because BAR is a number but CAR takes values.


> Wondering if you could make a lisp where `lambda` or `fn` required type annotations

> Someone implemented it in Common Lisp in the 80s I'm sure.

Even better, it's a standard part of Common Lisp: functions default to being 'typed' to take the universal type, but annotations can be used to declare any types you want (to include types like (integer 3 27), which specifies an integer between 3 and 27), which can be compiler-enforced.

I really don't understand why Common Lisp doesn't see more use. It's modelling clay for computation.


   \* add.shen *\

   (define add
      {number --> number --> number} \* type annotation *\
      X Y ->                         \* arguments list  *\
      (+ X Y))


There was a small thread on the Shen Google Group about adding docstrings [1].

There is an BSD version of Shen that can be forked and docstrings added by whomever wants to pickup the work. The language's footprint is small enough now at the moment, that now's the time to get the first chunk done.

The BSD version is pretty impressive, and could be turned into a great project if people picked it up. A lot of interest has been expressed, but it is the commercial version that is moving ahead with lots of improvements. Shen's creator, Mark Tarver has added Griffin, an optimizing compiler, concurrency, and HTML generator in the form of SML (Shen Markup Language).

It is a very fun project. The small set of instructions it is based upon Klambda, has since been ported to many languages - Ruby, Python, Lisp, Haskell and more. The SBCL port is the main one. Aditya Siram (Deech) has just created an Elisp port, shen-elisp! [2]

[1] https://groups.google.com/forum/#!topic/qilang/FHUNMvOyu2U [2] https://github.com/deech/shen-elisp


I personally use ClojureScript with type annotations from Plumatic (former Prismatic) Schema and it works really well. Obviously it's not the same as an actual typed language, but it gives me a good-enough starting point to leverage some typing information and perform some rudimentary (runtime) type checking. I also feel it's really nice as some kind of "inline documentation" to be able to see the type of your parameters (obviously this is a given benefit for statically/explicitly typed languages).


I have heard only good things about Schema, and I probably should have invested the time to understand and use it more intensively.


Just dive into it. After wanting to be a bit more descriptive and assertive about the input and output of certain functions in some code I was writing, I must have spent all of half an hour reading documentation and successfully adding Schema to my code. Might be a bit of a rose-tinted memory here in respect to the pastimate :) But it certainly is both easy to understand and use.


Might be off topic but I was interested in the "a big atom". Reagent is using a big atom and some small atoms to simulate component state -- which breaks hot code swapping. And I tried a way to abstract out component states into a single atom to fix it by building my own React like library. Now it's "two big atoms" on my side.


Yeah, after the app grew a bit, I had state scattered here and there. re-frame solves this with a big atom, and avoids expensive rendering every time the big atom updates with subscriptions. Subscriptions hold reactions, which only update if the underlying value changes.

The re-frame readme is epic and worth reading just for its own sake: https://github.com/Day8/re-frame

Not to get off-topic though! I am used to working with dynamic languages, but I really should work with a typed language. Elm looks like it offers many of the benefits of ClojureScript, but with typing as well.

Also, ClojureScript lets you write HTML and CSS in your code, but a quick web search indicates Elm may have gone further with incorporating CSS (?).


Can you talk a little more about your thoughts on one big atom? I've been looking at Redux and they also seem to follow this approach. The re-frame readme quotes the Elm Architecture as justification, but that same document goes on to describe nesting https://gist.github.com/evancz/2b2ba366cae1887fe621#nesting.

I come from a Haskell perspective and having one big blob of state sounds to me like it makes your type signatures less informative and increases the scope for error.


So, the one big atom solved two problems for me.

First, in Reagent/FRP, I was updating a view based on the value of an atom. This meant I had different default values in different atoms. The big atom let me unify where I stored values, and reuse values, without a performance hit. Second, the big atom made storing application state trivial: you can just throw the map/record in Redis or something.

However, the big atom is just a big map, and keys can be paired with any value, so it is not enforcing types. From a Haskell perspective (where I understand the program almost falls out of the types you define!), this probably does increase the scope for error.

This can be mitigated with Schema (which I never used effectively), logging changes to the console, and being able to see your default map easily (like, there's a map in one file which I load upfront, so I can see what values are there).

I'd welcome hearing from anyone with a more advanced or precise use of re-frame state.


Elm incoperates CSS the same way Clojurescript and React incorporates CSS.


Thanks, good to know.


Congrats to Evan. I'm still learning Elm and it has been such a pleasure. It's so much clearer to understand the code and go back to it later. I spoke with Evan at length at one of the regular Elm "hackathons" in SF and was so impressed how he thinks about long-term vision of Elm and prefers to take his time to ensure he gets it right to make Elm be around for a long while. Which is the reason I'm investing time into Elm. If you're in SF Bay area. Tomorrow (Wed) is the next Hack night a great place to talk to Evan and the small community around it.


I like Elm but its development really seems to rely on a single person. I saw this post on elm-discuss which is a pretty good summary of my thoughts https://groups.google.com/forum/#!topic/elm-discuss/AmxE3qAm...


Evan wants to design Elm as thoughtfully as he can, and has been deliberately resisting community evolution. Eventually it will get too big and too useful, and he'll lose the ability to make big breaking changes easily. So he's tried to maintain control of the direction of the language and community during these early years while he figures it out. He's trying to reduce the feedback loop and come up with the best possible base before it starts to scale.

It feels like it's stabilizing. I expect that over the next year or so this will change dramatically and it will become much more community driven.


' during these early years' should feature prominently in their docs/website if that is case.

If you go to http://elm-lang.org/ they make it looks like its production ready. No mention of breaking changes/beta ect. You have to choose one or the other .


The version number starting with a zero really ought to denote that, notwithstanding the JS crowd's seemingly fast and loose approach.


The Elm community is very strict about semver. Given this context, in Evan's defense, the 0.17 version is not a mistake as the API is still in flux.


It seems like communicating this approach to the community might be helpful for some. The poster's perspective is not unique (see the links in this thread). An evolution from benevolent dictatorship to democracy has advantages and precedent. Communicating with the community these intentions is important and a sign of respect and maturity. I think in itself it would be stabilizing.


for what it's worth, the compiler helps you find those breaking changes pretty quickly.

much better than having bugs sneak up on you in production


Yep every 'native' library needed arduous review process via github issues. I waited for over a month for elm overlords to approve my 'native use' library , they simply closed the issue.

Dropped elm for react and co. Now I have serverside rendering, code splitting, working debugger ect which was impossible with elm.

This was last year though so not sure if it is still the process. YMV.


It has changed, in that the language is moving away from Native code, and instead is trying to provide the web-platform as part of the language/core libs.

And for everything else, there's Ports. You can't use them in libraries, but for your own projects they're a much better JS FFI.


>And for everything else, there's Ports.

Ports are extremely tedious to use if you are doing anything even moderately complicated .


Same here and for that very reason I'll continue playing with Elm (it's fun) but ultimately I'm focusing more on learning Clojurescript as it seems to be the safer "sane" way out of JS/React country, at least for my professional projects.


Since people in this thread are likely to be elm enthusiasts and know what's going on in the ecosystem, what is the largest high quality elm app you know about and what is the largest high quality elm app that is open-source that you know about?

I've been doing backend work for a while and I'd like to see what is possible these days with elm.


I think NoRedInk, who employs Evan (author of Elm); they also host Elm meetups in SF and are a really friendly bunch.

On an unrelated note, I haven't found much prior work here but I think Elm on the backend (via Node.js) could be fantastic.


I've been thinking about this myself. I've been looking at doing some typescript stuff as I can share code between back and front-end still (and I'm moving into doing some IoT stuff in JS). I'd consider Elm if I could run it everywhere, but it feels to me like at the moment it is browser focused.


There are experiments with using Elm on the server via Node.

Since you mentioned NoRedInk, they had a sample project that bundled several available technologies: https://github.com/NoRedInk/take-home

It is worth noting that with the advent of 0.17, Elm on server is getting closer to reality. The issue now is for Evan to properly understand what the best approach is. My hope is that we will end up with something like Servant in Elm.

In a lot of things Elm is not aiming at WOM but WOFO. In other words, not for libraries that gets most word of mouth but libraries that get word of f-ing obvious. That requires a more deliberate and slower process but the payout is huge.


There's always Haskell. :)

On a slightly more serious note, I wonder if Haskell and Elm are similar enough that model-style code could be written in a shared subset and run on both sides.


They are close enough that people have produced tools like elm-servant that generates Elm code from Servant code.

https://github.com/mattjbray/servant-elm


"what is the largest high quality elm app you know about and what is the largest high quality elm app that is open-source that you know about?"

http://builtwithelm.co is a good place to start. My favourite big example is Dreamwriter (https://dreamwriter.co) by Richard Feldman. Warning not updated since e0.15.1 ~ https://github.com/rtfeldman/dreamwriter


Do you know any examples heavy with animations? E.g. similar that can be achieved with CSSTransitionGroup in React. While I can't use Elm in production app, I could dabble on it side projects, but I'm a little bit put off by the examples it has, they seem to not contain complicated appear/leave animations or animation managers. I think it's not yet solved?



I'm super excited for this change. I've been watching and waiting for a few weeks. It's a big ordeal for me personally, because I've got 10 weeks of daily elm tutorial content I've written so far at http://dailydrip.com/topics/elm that I'm now re-writing, but the changes are all for the better and the language adoption is bound to go up over time.

If you haven't yet tried Elm, give it a shot. A co-worker (hi Heath!) showed it to me 4(?) years before I got interested in it, and I brushed it off as a toy because I was against Functional Programming at the time for terrible reasons. It's actually one of the 'this feels like the future' technologies that's re-shaping how I think about programming these days. Huge kudos for the release!


I haven't dabbled in Elm much, but subscriptions look a lot like ordinary JS event handlers:

    Time.every second Tick
vs.

    Time.on('everySecond', tick)
Beyond baking an event emitter into the Time module and having a nice looking API, is there something I'm missing?


I don't know anything about Elm subscriptions yet. But there is a lot more to this stuff then just event emitters.

Things like:

* When an event/action/etc comes through, does it always call listeners synchronously? Can you change that and schedule events manually?

* How do you compose subscriptions/event handlers? This is usually the hardest part, and where simple event emitters really start breaking

* What about the lifecycle of the listener? What happens when it subscribes or unsubscribes? More importantly, what happens when the source that it subscribed to "shuts down"?

All of these things get pretty complicated and is the reason why various fields like FRP exist. Simple event emitters work immediately, yes, but they are a pretty terrible abstraction to build an app on.


Yeah the same questions popped up in my head. The natural end point to me looks more like Rx. Lifecycle and especially composition seem like big missing pieces.


Exactly these questions also came to my mind when I read the article. Subscriptions can get very tricky. Sometimes you want events to be synchronously fired, sometimes it's better when they are deferred into another eventloop tick. Unsubscription can also get quite tricky as you said.

I really wonder if Elm got a generic solution that fits all possible usage scenarios.


It looks like Subscriptions are just Signals with another name. I don't see any difference except that functions like map, foldp, etc. have been removed to discourage first-order use of them.


They key difference is that when you create an event emitter in JS, you now have a resource to manage. Where does that go in your app? In each component? How does the component know how to turn these off if it is no longer in use? In the root? How does the root know who needs what?

So basically, the difference is in resource management. The web socket example makes this clearer. You never have to ask "who owns the connection?" to use the connection.


> The web socket example makes this clearer. You never have to ask "who owns the connection?" to use the connection.

To be fair you can do this in javascript as well using a messaging pattern similar to elm. Many libraries like postal.js (synchronous) and msngr.js (asynchronous) support a messaging pattern where you can access resources without caring who owns them.


The fact that you can immediately imagine how it works and think that it is a very simple comncept, makes the changes in 0.17 even more awesome.

It turned something that is in real life difficult to manage, compose and scale, into something not just easy to grasp, but also simple to read and safe to execute.

Congrats on everyone involved in making this release happen.


`Time.every second Tick` returns a time-varying value it doesn't call a side-effecting callback. It generates a filtered event emitter if you will. Semantically it has almost no relation to your JS version, aside from both being function calls.


Ah, this explanation is the most cogent to me. So does the Elm runtime and/or compiler manage this as an event or callback under the hood?


First page of the Elm guide covers it pretty well: http://guide.elm-lang.org/

> No runtime errors in practice. No null. No undefined is not a function.

> Friendly error messages that help you add features more quickly.

> Well-architected code that stays well-architected as your app grows.

> Automatically enforced semantic versioning for all Elm packages.


to be fair, all these things do not seem to be dependent on this new Subscriptions thing, as in fact they were there even before.

I am sure the new idea is good, but as grandparent said, the examples fail to convey why this is better than what we had before.


The "new Subscriptions" thing replaces signals, which is not what GP thinks is "what we had before".


What I really want is a language with Elm's type system, simplicity, and syntax, but aimed for backend software instead of HTML apps and with strong support for an Erlang-style actor model of multicore, distributed concurrency. Basically something like Elixir, but with Elm's syntax and type safety. In the meantime Elixir will do for me, but I'd really like more type safety without going full Haskell.


Did you try dialyzer for Erlang[1] or Elixir[2]?

[1]: http://erlang.org/doc/apps/dialyzer/dialyzer_chapter.html [2]: http://elixir-lang.org/docs/stable/elixir/typespecs.html

Not sure it helps, it's on my todo list.


Despite some niceties like union types, Dialyzer is pretty limited. For example, here is example of something I would expect to be able to express in a modern type system but is not possible with Dialyzer (as far as I know):

    @spec foo[a: SomeProtocol & SomeBehaviour](a, a) :: a
I've also noticed that it lets through stuff that I would expect to fail to compile, so it's hard to trust as I would a type system like Elm's, Haskell's or Rust's. The Elixir devs have done a great job with the language, and it's great to see the resurgence of interest in BEAM as a result, but I still really wish they had taken the opportunity to build in a decent type system...


Akka[1] is exactly the library you're looking for. It's available for Scala[2], which lets you use both OOP and FP as needed. (It also runs in Java if you have experience with that.)

[1] http://akka.io/ [2] http://www.scala-lang.org/


But Scala is far from a simple language and Akka makes it even less so.


Scala is more forgiving than Haskell and the parent poster asked for something with Erlang-style actors, which are always going to be complex.

I really think this is the best option out there.


You could try f# or c# with http://getakka.net/


Then you'll probably be very excited to read about http://package.elm-lang.org/packages/elm-lang/core/4.0.0/Pro...


Well, BEAM has supervisors, supervision trees, loads of support for fault tolerance, automatic usage of multiple cores, and it easily scales to multiple nodes as well. Simple actor-based concurrency is possible in many languages.

Also, even if Elm were to get all that stuff, it'd still be compiling to JavaScript and aimed at web apps.

(Don't get me wrong, I'm super excited to see Elm getting support for message-passing lightweight processes. I love Elm, have used it myself for several projects, and think this looks great for web development. I just want something like Elm, but specifically geared towards large-scale backend services instead of front-end apps.)


No actually, if you read the announcement you'll find that Elm is keeping platform specific code in the Platform module, to not be locked into being a Javascript-only language forever.

So maybe it would take some time, months, years, but Elm could end up running on the BEAM.


Purescript? I moved over to it from Elm, exactly because I needed to share the code between frontend and backend and realized that I can't really use Elm on the backend without much effort and risk. Purescript is closer to Haskell than Elm though and as such less "beginner friendly". Monads, typeclasses all that scary stuff. But somehow I handle it okay.


pony is worth a look: http://www.ponylang.org/


Have you had a look at F#? fsharpforfunandprofit.com


For whatever reason the Elixir community doesn't seem to really strongly point people at dialyzer, but what you want is dialyzer, and yes you can use it with Elixir.


Bite the bullet and go full Haskell, it's not that hard, although it seems to appear that way from the outside.


This is marvellous. IMO Functional has always been a bigger deal than Reactive. Great to see more of that pursuit of simplicity paying off.


There is a nice talk from Erlang Factory 2016 called

"Making the Web Functional with Phoenix and Elm"

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


Stupid question from an interested outsider: how's a "subscription" different from a good ol' callback?


I think it is worthwhile stopping by the Elm slack channel to ask this. You have framed the question in a weird way. The answer is kind of "these things are not really related in any direct way" but I feel like you are asking a different question. Point is, ask on the slack channel and folks will help clarify :)


Just out of curiosity. I'm trying to decide which client-side framework/language to dive into, and it seems that many people consider Om Next a really nice step forward, away from "giant blob of state". My (uninformed) observation is that Elm does things the way Om (previous) did it: is that correct? Is Elm aiming to incorporate Om Next's advantages?


> My (uninformed) observation is that Elm does things the way Om (previous) did it: is that correct?

It's not, Elm doesn't use cursors and transactional mutations, I'd say the Elm architecture is closer to a pure single-store Redux: user actions are dispatched as Sub Action which are run through an update reducer (Action -> Model -> Model), which is then run through the view (Model -> Html) resulting in the new UI state.


As far as I understand Om.next still uses a "giant blob of state" - a global atom. It differs from re-frame/reagent in how you access this state, the global atom.


Elm does things the same way. However, PureScript has lenses so the same thing can be done if you're using the equivelant of Elm in purescript, purescript-pux


Say what you will about languages that compile to JS, but Elm code looks so elegant that I just want to use it for aesthetics alone. Major kudos to Evan for such a wonderful and powerful creation.


From the Lucid Synchrone paper referenced in the article:

"Synchronous languages are based on the synchronous hypothesis. This hypothesis comes from the idea of separating the functional description of a system from the constraints of the architecture on which it will be executed. The functionality of the system can be described by making an hypothesis of instantaneous computations and communications, as long as it can be verified afterward that the hardware is fast enough for the constraints imposed by the environment."

That sounds a lot like how functional programming works in a browser. If you assume function calls take zero time (or can be optimized so they're fast enough) then you end up with event handling and asynchronous I/O. Preemptive multitasking becomes a non-issue. But long-running computations (where you actually want to keep some CPUs busy for a while) need to be handled outside the system.


I got into studying FRP around 3 years ago for my senior project. Aside from a decent, clear explanation, there were hardly any actual implementations of this allegedly good paradigm (something Evan covered in his thesis, and the basis for Elm). It seemed like a paradigm that was full of promise and potential but failed to deliver in any worthwhile way.

(Such was the case for my senior project, studying the viability of Arrowized FRP in Elm. In short, I concluded that it was nothing but hell and nobody should bother.)

I am happy to seem Elm drop FRP, even if I wished it could be the savior of the method. At this point I think it's a troubled concept and should be limited to old theses.


I'm similarly ambivalent. Though Elm and it's flavour of FRP were more of a hobby (I never turned into an academically valuable thing :) ), I was still very interested in the roots of the system and how to use and improve it. I know the change was happening already, that signals were not used much in the Elm Architecture; I also understand and applaud the simplification. But I'm still a little sad to see FRP go, it's an interesting idea and does have potential IMHO.


Woah, still reading but seems like a big change considering FRP was somewhat fundamental to Elm.

[edit] Looks like a solid change driving Elm towards easier usage, Signals and Mailboxes were definitely something that took a while to wrangle correctly.


Elm is very cool and pleasant to use compared to JavaScript, but I have some reservations. The limited typeclass system (for numbers and such) seems... questionable. The interaction of what looks like pure declarative syntax and what is actually impure imperative semantics is confusing to me. I understand that the author wants to avoid monads and other perhaps somewhat confusing staples of functional IO, but I'm not sure the cost/benefit of doing it this way works out.

I will say that Elm is the best JavaScript-targeting platform I have tried! I have hopes for GHCJS, but it's not near Elm's level of readiness yet.


I don't think the semantics are any more imperative than IO in Haskell, it's just that there's a different abstraction used for dealing with it.

Moreover, Tasks are absolutely monadic, with `andThen` being the bind operator. Elm just chooses to focus on the individual use-case, as opposed to focusing on the broader abstraction.


What does that mean? I'm not sure how you could get more imperative than IO in Haskell; that's literally how the language deals with effectful imperative sequencing.

Which abstraction does elm use? As far as I can see, there is no abstraction. This is the problem. Effectful code in elm looks syntactically just like pure code.


I found that while things worked once it compiled, I spend most of my time staring at compilation errors, especially as I refactored. So I'm mostly trading time spend debugging subtle state errors with fixing compile type errors. It feels not as productive, since I'm usually looking at errors.

Also, I'm still new to FP, so if you go outside of the Elm architecture, you're going to run into problems, which you're use to solving with specific tools, but they won't be available. So you'll have to spend time learning how to compose things in a new way.


> So I'm mostly trading time spend debugging subtle state errors with fixing compile type errors. It feels not as productive, since I'm usually looking at errors.

Strange, because debugging subtle state errors seems far more time consuming to me than fixing compile-time errors. You have to launch debugging sessions or insert logging commands and step through reams of code, where compile-time errors tell you exactly where the problems are.


Yeah, it's true. Logically, I know it's better to catch it all at compile time. But it just feels things are broken all the time, since I don't get to watch my program run nearly as much as I use to.

However, when it runs, it usually does work. I think I'm just not as use to structuring my programs in FP yet.


I had trouble because the compiler errors were very hard to understand. If your code compiles then yeah, you can step through it. If your code does not compile and you don't understand what the problem is, then you're stuck. This makes me think it would be interesting to have a step-through compiler. I don't know if that even makes sense, but it sounds helpful.


Haskell has the option to run your code without type checking [1], so this isn't an inherent limitation to type checking.

[1] https://downloads.haskell.org/~ghc/latest/docs/html/users_gu...


Elm has always been "that language I dabble in every now and then but never have time for"... good to see it's evolving. Evan and Richard (creator and main evangelist, respectively) are a great team and I hope them the best (and I hope I get more time to mess around with Elm!).


Wow, this is a surprise. Kind of like a Haskell headline "A Farewell to Immutability". But sounds like the pros and cons have been well thought out for the intended use case.


Not quite that extreme. FRP has always been a very awkward way to express things, even within the functional/immutable world. FRP had already had it's (small) boom-bust before Elm came on the scene to give it a small revival.

This is a very good change for Elm.


One thing I'm wondering with elm is how does it deal with state across different components? I.e. where would you put the settings of the current user and how would you access that within one component? (By component I mean the (init,update,view,subscription))


Another approach is to use extensible records, which give you structural typing similarly to Typescript. This means that you can pass the exact same state record/object around to different components, but a particular component might only specify that the state needs to have a `user` property, whereas another might only specify that the state needs to have a `friends` property.


Since with The Elm Architecture parent always takes care of it's children you can create a "Context" and pass it along.


Does Elm have any nice interfaces for common JS frameworks? (like reagent / om in clojurescript, or angular2 for dart / typescript)


In general, you're unlikely to need them.

Instead of cobbling together disparate libraries for a virtual dom (React), state (Redux), immutability (Immutable.js), and types (Flow / TypeScript), the entire language and its core libraries are developed as a holistic (but still modular) unit. In this way, Elm is the BSD to JavaScript's GNU/Linux.

Strong typing and immutability are baked directly into the core language, elm-lang/html includes an efficient Virtual DOM, and Redux-style action / reducer cycles tend to naturally arise from "The Elm Architecture," and don't need significant support beyond what's already in the core language.

If you've bought into the React/Redux paradigm, it's worth giving Elm a shot: the entire language and core libraries are intentionally designed to more cleanly, reliably, and maintainably implement the same structure.


"In this way, Elm is the BSD to JavaScript's GNU/Linux."

Is there X such that X is the Plan9 to Elm's BSD?


Perhaps Urbit could fit that description?


Elm has JS interop via ports, which would allow you to mix or migrate towards elm.

https://evancz.gitbooks.io/an-introduction-to-elm/content/in...


Emphasis on the migrate, you do not want to have app with both JS and Elm for a long term perhaps.

In the main article: "I do not expect to be compiling to JavaScript forever, especially with WebAssembly on the horizon. The smaller the interface between Elm and JS, the easier it will be to support other platforms."

While I don't want to sound doom and gloom, the JavaScript support according to article is anomaly of today's browsers. So if you want to rely on two parts JS and one parts Elm type of thing, it's good to know it maybe gone.


Elm doesn't really "need" interfaces to react/angular/whatever, the Elm Architecture defines a standard way to write a reactive application in pure Elm (in a style similar to react/redux).


So Elm is only usable for new projects (or rewrites from scratch) and can't be "tried out" if you have some existing mess of a code and want to replace some especially ugly chunk of it (or write a new feature) - just to see how it goes?


No that's not true. Richard from NRI wrote a great blog post about just "trying out" elm in your React app.

http://tech.noredink.com/post/126978281075/walkthrough-intro...


We use Elm inside Angular in production. On https://circuithub.com/projects/ti/TIDA-00230 most of the drawing is Elm.


Ports were the way to do this in Elm. I don't know how it works in the new version.


They do, and have been made much clearer: http://guide.elm-lang.org/interop/javascript.html


elm-html gives you a very nice interface to virtual-dom, which combined with the Elm Architecture is all you need.


Hey! CodeHS is working on an Elm Course. The vision of the course is to make a more approachable version of SICP.

The course is still in development, but let us know if you're interested!

https://codehs.com/info/curriculum/elm


Has anyone upgraded a non-trivial app from 0.16 to 0.17? Is it pretty simple to rewrite moving from Signals to Subscriptions? Any advice?


It took me about a day and half to upgrade a good sized project, and most of that time was spent sorting out native code. If you don't use native code and are using StartApp then its a fairly trivial/methodical upgrade process.


I love Elm before but now it is even better! I'll make the switch even though I was almost done with my first app with it.


Is parsing json still an ugly mess? That was what put me off actually using it for anything.


Its a little wordy, but now that I'm used to it, it takes no time to write decoders/encoders. There is also a tool to automatically generate them from JSON input at http://noredink.github.io/json-to-elm/


didn't know about this! thanks!


Under "other cool stuff" it's mentioned that error reporting when parsing fails is greatly improved. Not sure if that's what you meant.


> A web handler threw an exception. Details:

> gen/pages/blog/farewell-to-frp.html: getFileStatus: does not exist (No such file or directory)

Some caching problem, it seems?


I reloaded and it worked.


So, is it still true to say, "You wish you could express your business logic with pure functions. But often you can't because the lack of immutability hurts performance in various ways. But ELM creates a 'sandbox' in which you can do so, by letting you write functions which work over time varying streams instead of stateful callbacks."

If not, which parts changed / how would you revise it?


I wouldn't say that it's about performance for Elm. Its virtual-dom has been shown to be wickedly fast with pure code.

It's more that real programs need real effects: you need to send HTTP requests, read from user input, etc. Elm gives you a managed way to deal with those effects, while keeping the program declarative, and making as much of the logic side-effect free as is possible.


Has the elm installation on Linux improved in recent months? Last time I tried my system's GHC was too new to install it from source and the node installation went kablooey in weird parts(too recent ncurses, the automatic "reactor" browser repl not finding the Html package etc...)


You can install elm with npm.


It should at least be able to compile with GHC 7.10 now.


For those like me who aren't familiar with Elm:

An Introduction to Elm

https://www.gitbook.com/book/evancz/an-introduction-to-elm/d...


The chat client thing is pretty interesting, but there's this little bit:

> Use the browser API — To get started you just create a new web socket! Well, then you need to open the connection. But do not forget to add an onerror listener to detect when the connection goes down and try to reconnect with an exponential backoff strategy. And ......

How does handling errors happen I wonder. If you take FB messenger for example, you would queue up a message but if the sending failed you would get an opportunity to retry/not send it at all.

I suppose in FB's case you could write your own subscription provider...


Say a magazine company wants to regularly send issues to a customer, and the customer signs up. Who has the subscription, the customer, or the magazine company? Which one subscribes?

According to Rx, it's the magazine company. Which one subscribes? The magazine company subscribes. It took me a while to realize this when trying to learn Rx concepts, which made it really confusing, since I've always seen the customer as being the subscriber, subscribing and owning the subscription.

It looks like Elm is the other way around compared to Rx, I think.


I suppose if anything it is the customer subscribes. But actually, in practice, it doesn't really feel quite like this because in FP you just have a bunch of functions and there isn't the concept of things 'owning' other things like you have in more OO based language. What actually happens is that you add a (sort of) listener to the subscription that fires a message in a particular update function, which manipulates some part of the model.


FRP = Functional Reactive Programming

> When I started working on my thesis in 2011, I stumbled upon this academic subfield called Functional Reactive Programming (FRP). By stripping that approach down to its simplest form, I ended up with something way easier to learn than similar functional languages. Signals meant piles of difficult concepts just were not necessary in Elm.


I have been learning some haskell, maybe I will dabble in elm. Watched a talk by Evan and was blown away by time-based sophistication.


FOAM is also subscription based, but then builds FRP on top of it: https://www.youtube.com/watch?v=-fbq-_H6Lf4


Can someone explain how the subscription API differs from signals, addresses, and ports? I'm not familiar with the "old" Elm so I can't judge what the change is like.


I wish Elm's blog had an RSS feed.


Are there type classes in Elm?


No, and they're not planned either. There has been much discussion about them in the years: https://github.com/elm-lang/elm-compiler/issues/1039


Looks like Elm moved closer to Pux's API by dropping the signals for `Html action`. Check out Pux if you're interested in the same architecture but for PureScript.

https://github.com/alexmingoia/purescript-pux


Wow, the buttons demo looks very, very close: http://guide.elm-lang.org/architecture/user_input/buttons.ht...

The biggest difference is that the Elm version of "start a simple application" encapsulates more boilerplate, but I guess pux can do server-side rendering?


Yeah, Pux can do server-side rendering, and PureScript can be used with webpack alongside other JS. PureScript also has a much easier FFI.


subscriptions are great for handling black hole callbacks - callbacks that you cannot return back control to the callie.

Examples of this would be web-socket , http-requests , etc.

however elm and cycle.js try to shoe-horn this idea everywhere - which I think is not needed.

Not every event needs to be subscribed to - it pollutes your global stream. Use global stream only when you need to deal with things that move out the execution context of your program.


Doing away with signals is a great move, everything else about the elm architecture felt so intuitive.

I'm excited to give elm another shot, and I yearn for the future he describes where web assembly makes elm a viable js replacement.


When I did the tutorials some weeks ago, I also had difficulty understanding Signals. In the time, it made more sense to me if it was called "Streams" instead, as I'm used to the concept of signals and slots from Qt, where a signal is an event that your widgets dispatch and slots are the functions that react to signals.

These subscriptions from Elm kind-of remind me the signals and slots mechanism of Qt..


Looks very good. I got stuck learning elm at about the point I wanted to integrate a call to a javascript function. Can't for the life of me remember if that involved signals or not. Will definitely try the tutorial(s) again when I get some more time because I really was enjoying everything else about the language and developing in it.


Congrats, you just invented Reactive Extensions...




Consider applying for YC's Fall 2025 batch! Applications are open till Aug 4

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

Search: