My question relates to the answer to another question: https://stackoverflow.com/a/11766789/3212958
In his answer, ertes writes the following type signature
select :: [a] -> [(a, [a])]
However, when select is actually used, ertes writes the following inside of a do block
(y, ys) <- select xs
Please help me shed some light on how the tuple (y, ys) matches the return type of select, namely [(a, [a])]. Is Haskell coercing the types at some point? (Does Haskell ever coerce types?) Is <- extracting a tuple of type (a, [a]) from the list monad that select returns?
Thanks, Max
--- EDIT: ---
@Lee reminds newbs to desugar before trying to reason about types. After making >>= explicit, it's more clear what's going on. After desugaring, the function in question looks like:
select xs >>= \(y, ys) -> fmap (y:) (perms (n - 1) ys)
And for lists, xs >>= f = concat (map f xs). So a better reading of (y, ys) in this context is as the signature of the function to map over the list.
In do notation,
do x1 <- action1
action2
is translated into action1 >>= \x1 -> action2
This means that if action1 has type m a for some monad m, then x1 has type a. It's not really coercing types, but rather 'unpacking' the value from the monadic action action1 and binding it to x1.
(y, ys) is of type (b, c)
The return type of select is of type [(a, [a])]
In <- the types are actually d and Monad m => m d. So we can write the following type equalities:
(b, c) ~ d
[(a, [a])] ~ Monad m => m d
Solving is easy. First substitute d from first equation into second equation:
[(a, [a])] ~ Monad m => m (b, c)
Now to see what's going on I will use a prefix form of [] type constructor (it's not valid haskell but you should get the idea):
[] (a, [a]) ~ Monad m => m ( b, c)
So
m ~ []
(a, [a]) ~ (b, c)
At this point the compiler checks that instance Monad [a] exists. The rest is easy:
a ~ b
[a] ~ c
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With