
Learning FP the hard way: Experiences on the Elm language - ohanhi
https://gist.github.com/ohanhi/0d3d83cf3f0d7bbea9db
======
davexunit
Really nice explanation and code samples. I'm glad to see more accessible
materials emerge for explaining what signals are. The Elm website already does
a good job, but I think the extra detail in this article will help more people
grok it.

I have done my own exploration in this area. I hack on a game engine written
in Scheme that includes a signal implementation, a declarative scene graph,
and a live coding environment via a REPL server. It's not as glamorous as Elm,
but I'm quite proud of it and I plan to make the first release soon.

[http://dthompson.us/pages/software/sly.html](http://dthompson.us/pages/software/sly.html)

An older blog post I did with code samples and a quick screencast when the
project had a different name:

[http://dthompson.us/functional-reactive-programming-in-
schem...](http://dthompson.us/functional-reactive-programming-in-scheme-with-
guile-2d.html)

~~~
ohanhi
Thank you! "Accessible" is precisely what I wanted the post feel like.

Sly seems very cool too, I hope it will help popularizing these ideas!

------
yellowapple
I think this is the first time the concept of currying has solidly clicked for
me; most explanations focus on the "your function should take one argument"
aspect more than the "your function should return a new function" aspect,
which meant that, until now, currying looked more like an obstacle than a
tool.

Thanks!

~~~
ohanhi
That's great to hear! I also had some trouble finding the gist of currying. As
you said, the _why_ is often missing in the explanations. Glad I could help
you in that regard.

------
crimsonalucard
So when I update ship, that means a new ship was created right? What happens
to the old ship? and how is recreating the universe for every iteration
efficient? Is there something tricky going on in the background?

~~~
rtfeldman
There is indeed something tricky going on: Elm uses persistent data structures
behind the scenes.

See this previous HN discussion about Elm's persistent data structures:
[https://news.ycombinator.com/item?id=7686272](https://news.ycombinator.com/item?id=7686272)

------
mcphage
You claim that this is reactive rather than imperative, but instead, it feels
imperative instead of object oriented.

You still have your "setup method":

    
    
        Signal.map show (Signal.foldp update initShip inputSignal)
    

and your "handle updates method":

    
    
        updateVelocity newVel (updateShooting isShooting (applyPhysics dt ship))
    

And the distinction between "set the ship's position to ship.position +
ship.velocity * dt" and "create a new ship similar to the old ship but the
velocity is ship.position + ship.velocity * dt" seems like splitting hairs.

It's not OO, definitely—but it doesn't feel like you're _doing_ anything
differently than you would if this was a purely structural program, even if
some of the details are different. If this was straight C, "update" would be a
method that gets called 30 times per second, and "main" would get called when
the game starts, and everything else would map pretty much line-for-line.

Similarly, the "functional-reactive" nature of it feel like an implementation
detail, rather than a different way of thinking about the code—in your update
method you still walk through the steps "was <\- or -> pressed? was ^ pressed?
Move the ship. Fire your gun. Change your velocity." Maybe some of them don't
need to be recalculated? Okay, but as the programmer you still need to
describe the same steps, even if some of them get optimized away.

And honestly, even going through the same steps, it makes it harder to
understand. Take your update function:

    
    
        updateVelocity newVel (updateShooting isShooting (applyPhysics dt ship))
    

Okay, so you have an applyPhysics method that takes a ship, and a dt. That's
pretty clear. And it returns... something, and that something gets passed into
updateShooting, and then what updateShooting returns gets passed into
updateVelocity. You have to go elsewhere to read that, okay, applyPhysics and
updateShooting both return ships. The same steps, written in a more imperative
syntax:

    
    
        applyPhysics(ship, dt);
        updateShooting(ship, isShooting);
        updateVelocity(ship, newVel);
    

Which (a) makes it more clear that a ship gets passed into each method, but
(b) also lets you pass in the more important parameter first, which aids
readability, and (c) lets you list the methods in the order that they occur,
rather than writing them in the _reverse_ of the order they occur. To at least
get the better argument order with Elm you'd have to write it:

    
    
        updateVelocity (updateShooting (applyPhysics ship dt) isShooting) newVel
    

Which is completely unreadable—you're reduced to counting parentheses to see
which method "isShooting" gets passed into.

~~~
ohanhi
Good feedback, thank you!

I will rethink some of the phrasing, especially on the reactive/imperative
references. To be honest, the reactive part in the example is rather slim
(arguably only the `Signal.foldp` is "reactive"), and it is so by design. I
wanted to describe the appeal of writing pure functions first off, and then
subtly bind the existing code to the signals at play. Obviously this is an
opinionated decision.

Regarding the update function, I refrained from using the infix operator just
to make the article a bit more approachable. Was I to write the code just for
myself, it would have been:

    
    
        ship
          |> applyPhysics dt
          |> updateShooting isShooting
          |> updateVelocity newVel
    
    

This is also the reasoning for the argument order.

------
jasim
Well explained, thanks!

