Bind
Usage
Short:
- Sequential Computation: do X, and once finished do Y, and once finished do Z
Long:
- Given a value,
a, that is stored in a box-like type,m - Extract the
afrom the box,m - Pass it into a function,
(a -> m b)- The function uses the value
ato compute a new value,b. - The function wraps the new value
binto the same box-like type,m. - The function returns a box,
m, that stores the new value,b.
- The function uses the value
- Refer to the
bvalue asaand repeatSteps 1-3until we run out of functions - The last function returns the final
bvalue that is stored in the same box-like type,m.
Definition
See its docs: Bind
Below, we'll show two instances for Bind:
- A flipped version of bind that shows how it relates to
FunctorandApply - The correct version:
-- in real definition, 'f' (functor) is really 'm' (monad)
class (Appy f) <= Bind f where
bind :: forall a b. f a -> (a -> f b) -> f b
infixl 1 bind as >>=
data Box a = Box a
instance Functor Box where
map :: forall a b. (a -> b) -> Box a -> Box b
map f (Box a) = Box (f a)
instance Apply Box where
apply :: forall a b. Box (a -> b) -> Box a -> Box b
apply (Box f ) (Box a) = Box (f a)
-- Wrong: Flipped order of two args!
instance Bind_ Box where
bindFlipped :: forall a b. (a -> Box b) -> Box a -> Box b
bindFlipped f (Box a) = f a
-- Correct order of args
instance Bind Box where
bind :: forall a b. Box a -> (a -> Box b) -> Box b
bind (Box a) f = f a
bind's type signature is weird. How did we ever come up with that? To understand it (and understand why we have the below 'derived functions'), watch Category Theory 10.1: Monads and refer to the code below for help in understanding it:
-- >=> the "fish operator" is
-- called "composeKleisli"
infix composeKleisli 6 >=>
-- see "(a -> m b)" as the definition
-- of `pure` from the `Applicative` type class.
composeKleisli :: forall m a b c. Functor f => (a -> m b) -> (b -> m c) -> (a -> m c)
composeKleisli f g =
\a ->
let mb = f a
in (bind mb g)
where
bind :: m b -> (b -> m c) -> m c
bind functor function = join (map function functor)
join :: m (m a) -> m a
join = -- implementation
Laws
Associativity
(This law enables "do notation", which we'll explain soon.)
Definition: (x >>= f) >>= g == x >>= (\x' -> f x' >>= g)
TODO: prove the above law using Box (a lot of work, so ignoring for now...)
Derived Functions
- If you have nested boxes and need to remove the outer one (
join):join (Box (Box a)) == Box a
- Make chained multiple
aToMBfunctions easier to read...- going forwards (
composeKleisli/>=>):ma >=> aToMB >=> bToMC >=> ...
- going backwards (
composeKleisliFlipped/<=<):... <=< bToMC <=< aToMB <=< ma
- going forwards (
if computeCondition then truePathComputation else falsePathComputation(ifM)- If you want
bind/>>=to go in the opposite direction (bindFlipped/=<<):ma >>= aToMB == aToMB =<< ma