type Gen s a = s -> (a,s)
t1 :: Tree Char
t1 = Branch 'B' (Branch 'F' Leaf Leaf)
(Branch 'C'
(Branch 'D' Leaf Leaf)
(Branch 'E' Leaf Leaf))applyGenToTree :: Gen s a -> Tree b -> Gen s (Tree (a,b))
applyGenToTree g Leaf s = (Leaf, s)
applyGenToTree g (Branch b l r) s0 =
(Branch (a,b) ll rr, s3)
where
(a, s1) = g s0
(ll, s2) = applyGenToTree g l s1
(rr, s3) = applyGenToTree g r s2Some of the types we’ve seen that involve generators…
fmap :: (a -> b) -> Gen s a -> Gen s b
always :: a -> Gen s a
andThen :: Gen s a -> (a -> Gen s b) -> Gen s bThe andThen may look confusing but take away the Gen s and it’s almost nothing:
This is like an inverse function application: argument first, then function, result.
Here is how the function would be defined with Gen s added back:
andThen :: Gen s a -> (a -> Gen s b) -> Gen s b
andThen g f s0 = (b, s2)
where
(a, s1) = g s0
(b, s2) = f a s1And how we’d use it to define something like threeRandoms
threeRandoms :: Gen Seed [Int]
threeRandoms =
rand `andThen` \x1 ->
rand `andThen` \x2 ->
rand `andThen` \x3 ->
always [x1,x2,x3]Wow — all the careful state-threading is now hidden! It is performed by andThen but here we can treat it as “behind the scenes.”
Here’s how we’d rewrite the tree-processing using andThen:
applyToTree g Leaf = always Leaf
applyToTree g (Branch b l r) =
g `andThen` \a ->
applyToTree g l `andThen` \ll ->
applyToTree g r `andThen` \rr ->
always (Branch (a,b) ll rr)Haskell has a special syntax called “do” syntax for “Monads” which support these operations. Eventually we’d be able to turn this into:
applyToTree g (Branch b l r) = do
a <- g
ll <- applyToTree g l
rr <- applyToTree g r
return (Branch (a,b) ll rr)Exercise? Many list operations could be defined to work on generators instead. For example, here’s the type of filter. Can you write filterGen?
The two monad operations:
return :: a -> m a
(>>=) :: m a -> (a -> m b) -> m b
The operator is called “bind”. Sometimes called “flatMap”, sometimes called “andThen”.
Maybe is a monad. Either is a monad (in the Right side). List is a monad. Gen is a monad.
Let’s define the two monad functions for Maybe.
bindMaybe :: Maybe a -> (a -> Maybe b) -> Maybe b
bindMaybe Nothing _ = Nothing
bindMaybe (Just a) f = f aFormula: 2a/b + (a-1)/(a+b)
formula a b =
safeDiv (2*a) b `bindMaybe` \x ->
safeDiv (a-1) (a+b) `bindMaybe` \y ->
returnMaybe (x+y)Haskell has a “do” syntax for monads.
Or, generalizing the division so we can substitute any monad there:
ghci> formulaG safeDiv 3 4
Just 1.7857142857142856
ghci> formulaG (\i j -> [i,j]) 3 4
[8,13,6,11]