
More fun with reactive-banana-automation - edward
http://joeyh.name/blog/entry/more_fun_with_reactive-banana-automation/
======
sfvisser
What I love about Monad and Applicative interfaces is that I can read that
code and almost immediately fully grasp what’s going on without having a clue
about the underlying library.

There are a bunch of (well named) functions and control flow. No boilerplate.

~~~
jstimpfle
> no boilerplate

Well, compare to

    
    
        PowerChange inverterPowerChange(Sensors *sensors)
        {
            if (sensors->lowpower)
                return PowerOff;
            if (sensors->wifiusers > 0)
                return PowerOn;
            return sensors->fridgePowerChange;
        }
    

in a more traditional language. Nobody would make a fuss about that code.

~~~
kryptiskt
It doesn't do that. The one in the post composes a bunch of other Behaviors,
see the lowPower one further down in the article for an example, it's not
polling a bunch of variables. Then it is all wired up to react to events.

~~~
darkkindness
I think that, while the lack of type annotations on every variable is great
since hiding boilerplate is great, it could be confusing to the uninitiated.

To elaborate, lowpower etc. on this line are Behaviors, which emit values by
time:

    
    
        react <$> lowpower <*> fridgepowerchange <*> wifiusers
    

while lowpower, fridgepowerchange, wifiusers in the react function bind to the
values that are emitted by the Behaviors. (Just by looking at the code we can
infer that their types are Bool, (Num a, Ord a) => a, and PowerChange
respectively.)

    
    
        react lowpower fridgepowerchange wifiusers
                | lowpower = Just PowerOff
                | wifiusers > 0 = Just PowerOn
                | otherwise = fridgepowerchange
    

None of these are simply state variables!

Although this might have confused GP, I think this is nice since we can
associate the name 'lowpower' for its semantics (The low power signal) and not
have to worry about "this lowpower is a Behavior while that lowpower is a
Bool".

~~~
tantalor
So is it confusing or obvious? Pick one

~~~
marcosdumay
The code behavior is obvious once you know Haskell. The code simplicity
confuses people that don't know the language and think it is something much
less powerful than it actually is.

~~~
tantalor
In that case, why not just write everything in perl?

~~~
KirinDave
We actually did for a long time. It wasn't so bad, I guess? Certainly not
worse than Python, to me.

But the value of writing this kind of code in Haskell is that Haskell makes
code that couples very abstract interfaces VERY easily. This is really hard to
explain without some examples, so I'm going to give you an example.

Here, let me show you from real code. I'm going to tweak some endpoint names,
but this is real code I'm going to ship next week:
[https://gist.github.com/KirinDave/9b4380376f9f748bcf0f8440de...](https://gist.github.com/KirinDave/9b4380376f9f748bcf0f8440decae517)

What's cool about this code is that I'm describing a "generic" radAPI service
with a bunch of endpoints stripped out. Everything is parameterized around 3
generic ideas: "p", the Storage service. "Patchable", a strategy for applying
patches to a storage service (exposing runPatch), and "CanValidate", a
strategy for authenticating requests based on some sort of stored string, auth
headers, and body contents.

This is even better than mocking, because instead of deeply coupling the
structure of my code to my tests, I only couple the capabilities.

