# Imperative OOP Ceremony: do-Notation Pt. 1

1 Apr 2015

### Sections

In the last tutorial we saw how Programmable Fluent Interfaces can be implemented and that they are referred to as Monads in FP lingo. We will now start to use Haskell's built-in `Monad` type class instead of our own `Fluent` interface...

``````import Prelude hiding ((.))
x.f = f x

data Shape a = Circle { radius :: a } deriving (Show)

return = Circle``````

...but we will keep on using our own method synonyms `bind` and `make`.

``````bind = flip(>>=)
make = return``````

Everything should be working as before.

``````import Control.Monad
import Control.Applicative
import Data.Functor
import Prelude hiding ((.))
x.f = f x

data Shape a = Circle { radius :: a } deriving (Show)
instance Functor Shape where { fmap = liftM }
instance Applicative Shape where { pure = return; (<*>) = ap }

return = Circle

bind = flip(>>=)
make = return

-- show
doubleShapeArea(r) = make(r * sqrt(2))

circ = make(2) :: Shape(Double)

main = do {
print(circ);
print(circ.bind(doubleShapeArea));
}
-- /show``````

Let's add a redundant `.bind(make)` to the method chain (it trivially returns its argument) and wrap both `doubleShapeArea` and `make` in closures in order to reflect the values being passed through the method chain.

``````import Control.Monad
import Control.Applicative
import Data.Functor
import Prelude hiding ((.))
x.f = f x

data Shape a = Circle { radius :: a } deriving (Show)
instance Functor Shape where { fmap = liftM }
instance Applicative Shape where { pure = return; (<*>) = ap }
return = Circle

bind = flip(>>=)
make = return

area(Circle r) = r^2 * pi

doubleShapeArea(r) = make(r * sqrt(2))

circ = make(2) :: Shape(Double)

-- show
main = do {
print(circ.bind(doubleShapeArea).bind(make));
print(circ.bind(\(a) -> a.doubleShapeArea).bind(\(b) -> make(b)));
}
-- /show``````

As we can imagine, `a` is bound to `circ.radius`, i.e. `2.0`, and `b` is bound to `radius` of a `Circle` object with twice as much area as `circ`, i.e. a radius of `2.8284271247461903`. Both `a` and `b` exist only inside the closures `\(a) -> a.doubleShapeArea` and `\(b) -> b.make`.

But, if we chose to bind `\(b) -> b.make` to `doubleShapeArea` inside the closure `\(a) -> a.doubleShapeArea`, `a` remains available to `make` and we can apply `make` to `a` instead of `b`, thereby ignoring `doubleShapeArea`'s return value.

``````import Control.Monad
import Control.Applicative
import Data.Functor
import Prelude hiding ((.))
x.f = f x

data Shape a = Circle { radius :: a } deriving (Show)
instance Functor Shape where { fmap = liftM }
instance Applicative Shape where { pure = return; (<*>) = ap }
return = Circle

bind = flip(>>=)
make = return

area(Circle r) = r^2 * pi

doubleShapeArea(r) = make(r * sqrt(2))

circ = make(2) :: Shape(Double)

-- show
main = do {
print(circ.bind(\(a) -> a.doubleShapeArea.bind(\(b) -> make(b))));
print(circ.bind(\(a) -> a.doubleShapeArea.bind(\(b) -> make(a))));
}
-- /show``````

We can also make some computations with `a` and `b` like `sqrt(a^2 + b^2)`, which yields the radius of a circle that combines the area of two circles with radius `a` and `b`.

``````import Control.Monad
import Control.Applicative
import Data.Functor
import Prelude hiding ((.))
x.f = f x

data Shape a = Circle { radius :: a } deriving (Show)
instance Functor Shape where { fmap = liftM }
instance Applicative Shape where { pure = return; (<*>) = ap }
return = Circle

bind = flip(>>=)
make = return

area(Circle r) = r^2 * pi

doubleShapeArea(r) = make(r * sqrt(2))

circ = make(2) :: Shape(Double)

-- show
main = do {
print(circ.bind(\(a) -> a.doubleShapeArea.bind(\(b) -> make(sqrt(a^2 + b^2)))));
}
-- /show``````

Let's indent our code to reflect the Method Cascade.

``````import Control.Monad
import Control.Applicative
import Data.Functor
import Prelude hiding ((.))
x.f = f x

data Shape a = Circle { radius :: a } deriving (Show)
instance Functor Shape where { fmap = liftM }
instance Applicative Shape where { pure = return; (<*>) = ap }
return = Circle

bind = flip(>>=)
make = return

area(Circle r) = r^2 * pi

doubleShapeArea(r) = make(r * sqrt(2))

circ = make(2) :: Shape(Double)

-- show
main = do {
print(
circ.bind(\(a) ->
a.doubleShapeArea.bind(\(b) ->
make(sqrt(a^2 + b^2))
)
)
);
}
-- /show``````

As we can see, with each `bind` we add a new variable to the scope of the Method Cascade.

Side note: I say variable instead of value because values declared in Method Cascades can be redeclared in an inner closure, thereby overwriting a previously declared value of an outer closure. This happens in `circ.bind(\(a) -> a.doubleShapeArea.bind(\(a) -> make(a)))`, where `a` is been bound to the `radius` of `circ` and then to the `radius` of the return value of `doubleShapeArea`.

## do-Notation

Let's change our indentation step by step in order to reflect this pattern. First, we append the closing parenthesis of the Method Cascade to the innermost closure.

``````import Control.Monad
import Control.Applicative
import Data.Functor
import Prelude hiding ((.))
x.f = f x

data Shape a = Circle { radius :: a } deriving (Show)
instance Functor Shape where { fmap = liftM }
instance Applicative Shape where { pure = return; (<*>) = ap }
return = Circle

bind = flip(>>=)
make = return

area(Circle r) = r^2 * pi

doubleShapeArea(r) = make(r * sqrt(2))

circ = make(2) :: Shape(Double)

-- show
circ' =
circ.bind(\(a) ->
a.doubleShapeArea.bind(\(b) ->
make(sqrt(a^2 + b^2))))

main = do {
print(circ');
}
-- /show``````

Now we seperate the `.bind(\(...) ->` snippets and align the Method Cascade.

``````import Control.Monad
import Control.Applicative
import Data.Functor
import Prelude hiding ((.))
x.f = f x

data Shape a = Circle { radius :: a } deriving (Show)
instance Functor Shape where { fmap = liftM }
instance Applicative Shape where { pure = return; (<*>) = ap }
return = Circle

bind = flip(>>=)
make = return

area(Circle r) = r^2 * pi

doubleShapeArea(r) = make(r * sqrt(2))

circ = make(2) :: Shape(Double)

-- show
circ' =
circ              .bind(\(a) ->
a.doubleShapeArea .bind(\(b) ->
make(sqrt(a^2 + b^2))))

main = do {
print(circ');
}
-- /show``````

As we can see, Method Cascades that use a Programmable Fluent Interfaces introduce a variable to the scope of each chained method, in our case `a` and `b`, that are extracted from objects that implement the Fluent Interface. It's like writing `a <- circ` and `b <- a.doubleShapeArea`. Haskell uses this pattern extensively and therefore provides syntactic sugar called do-notation that allows for using this patterns exactly like that.

``````import Control.Monad
import Control.Applicative
import Data.Functor
import Prelude hiding ((.))
x.f = f x

data Shape a = Circle { radius :: a } deriving (Show)
instance Functor Shape where { fmap = liftM }
instance Applicative Shape where { pure = return; (<*>) = ap }
return = Circle

area(Circle r) = r^2 * pi

doubleShapeArea(r) = return(r * sqrt(2))

circ = return(2) :: Shape(Double)

-- show
circ' = do {
a <- circ;
b <- a.doubleShapeArea;
return(sqrt(a^2 + b^2));
}

main = do {
print(circ');
}
-- /show``````

The naming of Haskell's built-in `return` (which we called `make`) reflects that Method Cascades that use a Programmable Fluent Interface are powerful enough to model computations.