
Selecting a platform: JavaScript vs Elm vs PureScript vs GHCjs - g4k
http://mutanatum.com/posts/2017-01-12-Browser-FP-Head-to-Head.html
======
floatboth
BuckleScript (OCaml)
[https://github.com/bloomberg/bucklescript](https://github.com/bloomberg/bucklescript)
is the only one that produces reasonable output that doesn't require large
runtime libraries all the time.

Koka [https://github.com/koka-lang/koka](https://github.com/koka-lang/koka) is
a very interesting research language that focuses on explicitly specifying
effects in types. It even deconstructs Haskell's notion of purity into "throws
exceptions" \+ "may never terminate". Unfortunately, the code generation
(which BTW exists for both JS and C#) is uh… not very good.

But honestly, I haven't felt the need to use a functional language in frontend
development. JavaScript (ES6) is good enough, and it's actually supported in
browsers, so you can develop without any compiling, and only use Babel to make
production builds. If the project is not small, use TypeScript to add some
type safety.

~~~
dhucerbin
Currently I'm writing in Purescript but I'm constantly checking BuckleScript
and I'm liking direction of it. What is OCaml polymorphism story? Does it have
analogue of typeclasses? I'm currently using Purescript for writing build
steps for webpack and I benefit from Haskell ideas like lenses, refolds and
free monads. It would be great if I could transfer those tools. Maybe you
could point me to some literature about transforming recursive data structures
(ASTs) in OCaml? Maybe thera are some interesting tools and techniques?

------
hongbo_zhang
It is very cool to see different type safe Alt-JS compared, I made a gist here
which includes Elm, PureScript, BuckleScript and ClojureScript, add your
favorite one here:
[https://gist.github.com/bobzhang/9f27a5a0bd730e8d3503bf5d058...](https://gist.github.com/bobzhang/9f27a5a0bd730e8d3503bf5d058a58a7)

~~~
sjrd
I added Scala.js in the comments.

------
leshow
"TEA is not composable, but through brute force. ... you are stuck building
and maintaining some giant types, and writing a ton of boilerplate. The ways
around this problem are fairly weak, and amount to, “don’t write components”
..."

This has basically been my experience with Elm. But don't say that Elm is
boilerplate heavy to any elm-acolytes, they will stick their fingers in their
ears and go "nananananana"

~~~
gjem97
Can you be more specific about what boilerplate is necessary?

~~~
leshow
Anything that is usually solved with something like typeclasses, or module
functors, or inheritance can only be solved in Elm with typing lots and lots
of concrete implementations.

Other things can't be solved at all, since Elm is so tightly coupled to TEA.

------
boubiyeah
Happy user of typescript here. imo, pure FP is just like pure OO: it's just
not very good. Why constraint ourselves? The world is not pure, our programs
don't become ANY better because of the IO monad (Task in Elm); Let's stop
wankering or at least, just do it for the math and the research value but
let's not kid ourselves it's very useful.

~~~
retrogradeorbit
> The world is not pure

TL;DR: The 'impurity' of the world is an illusion created by our brains.

I have a physics degree and I completely disagree. The world IS pure.

Think of it like this: Time is the successive application of a pure function
that takes the old universe as an argument and returns the new universe. All
science models the real world like this. This is the foundation of
mathematics. Nowhere in physics or maths do we mutate anything. Even quantum
applies this perspective. This is what leads to the many worlds interpretation
of quantum.

What's actually going on is your brain is such a powerful illusion machine
that it has convinced 'you' that the world is composed of 'objects' that
'change'. This is entirely inside your brain. It is a side effect of the
perception process inside your brain. It does not mean the real world is
actually composed of 'objects' that 'change'.

This illusion is so strong that we then go on to model the real world inside
computers with 'objects' that 'change'. This is a mistake that leads to no end
of problems.

Once you realise the world is immutable, and that the process of time is a
function, and that what we see as time is actually a succession of immutable
'universe-values', you then start modelling your problems like this. And then
you realise what a better fit FP is for modelling the real world. And then you
realise why science models the world using mathematics... that is functions
and values... which are immutable.

When I argue this with OO developers I ask them "Is the real world mutable, or
immutable?" When they answer mutable, I then ask them to go back to last
Tuesday and change their lotto numbers. They can't. It's almost as if the
past.... is immutable! And the present becomes the past the very moment it
comes into being. And the future is unknown.

The present also cant be changed. We can affect the future by using our
muscles to apply 'forces' to the 'universe-value' thereby changing the way the
time-function of the universe returns the new-universe value (the future), but
we cannot reach in and alter any of these immutable values directly, not the
past, the present, or the future.

~~~
daxfohl
What physics class do they teach all this in? I must have missed that one....

"Many worlds" is more philosophy than physics, isn't the most accepted
interpretation, and even going down that path leads to lots of edge cases that
could still imply impurity.

Besides, if the world is pure, and OO is part of the world, then OO must be
pure too so what's the problem?

~~~
soijioeiofj
Even calling any of this "philosophy" is too much credit. This is more like
shit you say to your dog when you're stoned.

------
wmfiv
In addition to the options identified in the article definitely take a look at
ScalaJS and ClojureScript. I've used ScalaJS quite a bit and it's a more or
less flawless experience.

~~~
pkasireddy
How does ScalaJS compare to these other libs in terms of building browser UIs?

~~~
edko
It compares pretty well. It is possible to define Scala bindings to JS
libraries, so you can use them more or less seamlessly. Bindings to the most
popular ones (jQuery, React, etc.) are already defined, and actively
maintained. It is relatively simple to add your own. A nice thing is that,
since Scala is a strongly-typed language, you get code-completion and
refactoring "for free". However, if you prefer to use dynamic typing, ScalaJS
lets you do that easily too.

Also, like the grandparent comment said, ClojureScript is a very nice language
too, with powerful tooling.

The nice thing about ScalaJS and ClojureScript is that they both can run on
the browser, and on a JVM backend. Scala also has an LLVM backend that is
being actively developed, but on its early stages. (ScalaJS is very mature and
performant)

------
chrislloyd
I'd be very curious to hear about the OPs specific experience with Flow. I've
found the opposite to be true of Flow vs Typescript with the added benefit
that Flow is easy to integrate into an existing codebase.

~~~
lloyd-christmas
> with the added benefit that Flow is easy to integrate into an existing
> codebase.

I converted our Node codebase to Typescript and had no problems at all. I
don't know much about Flow, but what is it that makes you think it's easy
comparative to Typescript?

------
boothead
Purescript does have very workable solution for client and server sharing
code:

[https://hackage.haskell.org/package/servant-
purescript](https://hackage.haskell.org/package/servant-purescript)

I'm using this with Halogen and it works great

------
tomphoolery
> Here are some reasons to not choose JavaScript: It’s JavaScript.

Was this really necessary? I stopped reading your post after I saw this
because I got bored and no longer take you seriously.

~~~
keithnz
From a functional programming point of view, the fact it is javascript is
almost the opposite of everything you tend to appreciate about your functional
language of choice. So that simply counts it out for some people. However you
an still do functional programming in js, and making use of typescript and
ramda is a pretty good base for doing it. (well, this is what I do anyways). I
find this a much easier approach when blending all kinds of javascript
libraries together than using a cross compiler .

~~~
graphememes
It also makes the writer hard to take seriously. Low blows never shine
brightly.

------
sk1pper
> I’m not even going to consider a system valid without managing IO in some
> way. So yes, all flavors of Lisp are off the table as well.

We're talking functional in the context of JavaScript, I think ClojureScript
deserves more of an explanation on why it doesn't even qualify. That is, if
you're trying to hold to the "neutral as possible" thing in the beginning.

~~~
pka
Clojurescript doesn't have a way of managing IO (i.e. types.)

~~~
iLemming
Clojure has something that arguably better than most static type systems, it
has Clojure.spec

~~~
pka
But it's not static. Pre/postcondition runtime checks can be implemented in a
static language as well.

------
paulddraper
When did every blog start having 22pt body and 62pt headers?

Those are the font sizes I used as a 4th grader trying to write a four page
essay with 500 words.

~~~
cholantesh
Very distracting; makes me long for the academic style of sites like
Kernighan's [1] or Stallman's[2].

[1]
[http://www.cs.princeton.edu/courses/archive/fall14/cos109/](http://www.cs.princeton.edu/courses/archive/fall14/cos109/)

[2][https://www.stallman.org/archives/2016-nov-
feb.html](https://www.stallman.org/archives/2016-nov-feb.html)

They'd be even nicer if the text was inverted, though.

------
nilkn
I've recently used Elm for a real-world internal tool and was looking over the
PureScript documentation today to see whether it'd be worth looking at
PureScript in the future. I was disillusioned with the boilerplate of writing
JSON decoders and encoders in Elm.

I quickly stumbled across this:

[https://github.com/slamdata/purescript-
halogen/blob/master/G...](https://github.com/slamdata/purescript-
halogen/blob/master/GUIDE.md)

This is pretty much the Elm Architecture, except fully understanding every
detail there requires the reader to be conversant with some pretty hairy
concepts, including free monads and the Free functor. That's not just
something that's under the hood. It's built right into the user-facing API,
and the user even has to tend to this free construction when writing `eval`
functions by manually writing lines like `pure next` or `pure (continue
value)`, which occur in the first example.

It seriously concerns me that the user will have to write lines that they
couldn't truly understand without understanding free monads, because frankly
nobody new to Haskell and PureScript is going to be comfortable with free
monads until they've spent some serious time with the language.

I happen to be very well-versed in Haskell so this stuff is not an issue for
me -- in fact the use of Free here is not only clever but kind of beautiful --
but I wouldn't really want to onboard someone onto a PureScript project who'd
never used Haskell or PureScript before and didn't even know what a functor
was. "Why do I have to write this `pure (continue value)` line? What does that
mean?" \-- "Oh boy... grab a seat and clear your schedule."

Some boilerplate for JSON decoding looks pretty tame in comparison, to be
honest.

~~~
purescript
Halogen is not the only option for building web applications with PureScript.
There are simpler options like Pux and Thermite, which are possibly much
easier to teach. Halogen is optimized for a different use case.

~~~
nilkn
Thanks! Both of those definitely look more beginner-friendly or at least
easier to teach. I'm going to have to look more into PureScript in the coming
days.

------
ruethewhirled
Can anyone explain what is meant by "managing IO" in the statement "I’m not
even going to consider a system valid without managing IO in some way. So yes,
all flavors of Lisp are off the table as well."? Is that like monads?

~~~
damncabbage
It means restricting to where you can perform IO actions, eg. printing to a
log, writing to a shared area of memory, etc.

Haskell does this by representing IO actions as values, eg. "IO String"
(something like "IO<String>", for people more familiar with that syntax),
representing an IO action that, when later evaluated, will yield a string that
you can use in subsequent actions.

Haskell's "main" (entry-point) function is a value of type "IO ()" (IO of a
value representing nothing useful; you don't get anything out of it, so you
just have a nothing placeholder). When a Haskell program is run, it ostensibly
(hand-waving here) takes that IO value and interprets it, performing the
action IO.

You have functions like putStrLn (print a line) that takes a String, and
returns an "IO ()" . Accordingly, if you have

    
    
      main = putStrLn "Hello, World!"
    

... you have a value that lines up with the expected return value of main "IO
()". More complicated examples, like

    
    
      main =
        readLn >>= (\x -> putStrLn ("Hello, " ++ x))
    

... are doing the same thing (checking the types line up), just with more
moving parts (the Monad thing you mentioned, which we're using to relate the
"read line" function with the "print line" function).

The key bit is that it's just "IO Blah" values standing in for IO actions, and
like jigsaw pieces, these IO-returning functions only fit together where the
types line up, restricting how you can use them.

Monads are tangential to this; the type-checking of that jigsaw puzzle is what
matters here.

------
Vinnl
Excellent overview. I wonder if the author also had a reason for skipping
tslint, other than perhaps not knowing about it?

Edit: Also, why do fewer and fewer sites have an RSS feed? :(

~~~
dualogy
> Edit: Also, why do fewer and fewer sites have an RSS feed? :(

Bit sad, that. Somehow it happened that a critical mass of bloggers/readers
moved over Google Reader while during the same period all those social-feed
web apps kept gaining momentum, then Reader shut off.. things can change like
that over a decade or so. A 20-year-old today was perhaps 7-10 when XML feeds
were hot currency. I'm still content with my numerous working subscribed feeds
in Thunderbird though, can't catch up as it is.

------
banashark
I'd like to put forth Fable as a recommendation.

It was briefly mentioned in another comment, but was written off for it's lack
of momentum, community, and libraries.

I'll respond to these important concerns one by one:

Momentum: The fable project began last year. There are still active
discussions about tweaks getting it to v1.0, but already there is enough there
to make complete applications. There isn't hackernews/reddit hype, but the
gitter is busy and there are some using it in production already.

Community: I assume that the concern with the community is that it isn't
large. F# has never had as large of a community in any of its incarnations
compared to mainstream OO-first languages, but the community has always been
there to help me out and I've never gone more than a day or two waiting on an
answer to a library/language question (most fable related questions are
answered very quickly on gitter). The latter fact alone makes it more
impressive to me than some other communities. Community is also important
because of the amount and variety of libraries that are created for a
language. I'd argue that this isn't as important for transpiled languages as
it is for separate compiled languages, where for example a ruby library can't
be used in python, but I can use any javascript library in fable.

Libraries: Library usage is interesting when talking about transpiled
languages, and mostly depends on the Dynamic and Foreign interfaces available.
Because of Fable's dynamic abilities, I can dynamically call any javascript
code I need to. I use this for a couple of libraries in the React-Native
application I'm building using Exponent. The other method is Foreign
interfaces, which is fantastic in fable because of how the F# type system (and
inference) works in the first place. There is a utility to convert from
typescript definitions to fable definitions (some will need tweaking
afterwards for greater type safety) which adds a ton of libraries itself. I'd
argue because of that fact that Fable has more libraries than any other
functional-first transpile-to-js language!

Here is a example repo I put up earlier with full-stack F# with live-reloading
on the client and server. [https://github.com/Banashek/Universal-FSharp-
Samples](https://github.com/Banashek/Universal-FSharp-Samples)

I'm using a setup like this on a current project deployed with docker-compose
to digitalocean.

Full-stack F# has been nice to work with so far.

One really nice experience I had was being able to reuse viewmodels and their
validators.

Android/iOS -> Exponent

Web -> Fable-Elmish

Server -> Suave

I had viewmodels and partial validation functions which could sit in a shared
folder and be referenced by all of the projects.

I change it in one place, and I can update all 3 instantly. All of the rest
calls depend on the types definition, so I didn't have to do anything after
adding a new property to the type and saving the document. The server
reloaded, the frontend reloaded, the mobile app reloaded.

I'm not sure If I'll keep it that way, as coordinating production updates is
something I haven't fully figured out yet, but for now it's neat to explore.

Would I recommend someone who doesn't know functional programming to switch
their applications to fable? No. Would I recommend fable to someone familiar
with functional programming looking for a better way to manage their ui? Yes.

