I am currently in need of a bit of brain training and I found this article on Haskell and Monads
I'm having trouble with exercise 7 re. Randomised function bind.
To make the problem even simpler to experiment, I replaced the StdGen type with an unspecified type. So instead of...
bind :: (a -> StdGen -> (b,StdGen)) -> (StdGen -> (a,StdGen)) -> (StdGen -> (b,StdGen))
I used...
bind :: (a -> c -> (b,c)) -> (c -> (a,c)) -> (c -> (b,c))
and for the actual function impelemtation (just straight from the exercise)
bind f x seed = let (x',seed') = x seed
in f x' seed'
and also 2 randomised functions to trial with:
rndf1 :: (Num a, Num b) => a -> b -> (a,b)
rndf1 a s = (a+1,s+1)
rndf2 :: (Num a, Num b) => a -> b -> (a,b)
rndf2 a s = (a+8,s+2)
So with this in a Haskell compiler (ghci), I get...
:t bind rndf2
bind rndf2 :: (Num a, Num c) => (c -> (a, c)) -> c -> (a, c)
This matches the bind curried with rndf2 as the first parameter.
But the thing I don't understand is how...
:t bind rndf2 . rndf1
Suddenly gives
bind rndf2 . rndf1 :: (Num a, Num c) => a -> c -> (a, c)
This is the correct type of the composition that we are trying to produce because
bind rndf2 . rndf1
Is a function that:
takes the same parameter type(s) as rndf1
AND takes the return from rndf1 and pipes it as an input of rndf2 to return the same type as rndf2
rndf1 can take 2 parameters a -> c and rndf2 returns (a, c) so it matches that a composition of these function should have type:
bind rndf2 . rndf1 :: (Num a, Num c) => a -> c -> (a, c)
This does not match the naive type that I initially came up with for bind
bind f :: (a -> b -> (c, d)) -> (c, d) -> (e, f)
Here bind mythically takes a function that takes two parameters and produces a function that takes a tuple in order that the output from rndf1 can be fed into rndf2
why the bind function needs to be coded as it is
Why the bind function does not have the naive type