Problem combining monads <sigh!>

I think I was looking at the page http://learnyouahaskell.com/for-a-few-monads-more#state a few paragraphs under the H3 “The join function”. It mentions “…we wanted to combine several of them into one, be it with <*> or >>=,…” Now I'm actually quite comfortable with Applicative syntax, and am preferring it in places where older texts and examples use monads or fmap etc. (I look forward to an updated standard where Monads are derived from Applicatives.) (Aside: is there a "history" function in GHCi to show the last few commands I typed?) So, I tried a GHCi example starting with: λ>(+7) <$> [1,2,3] λ>[(+7), (*2)] <*> [1,2,3] no sweat. Now use >>= to do the same thing: λ>[(+7), (*2)] >>= [1,2,3] -- nope (I'll spare the error messages, which inspired some of the other things to try, some of which were just to explore the errors themselves) λ>[(+7), (*2)] <<= [1,2,3] -- nope λ>[(+7), (*2)] =<< [1,2,3] -- nope λ>[return (+7), return(*2)] =<< [1,2,3] -- nope (Use a single function as a simpler starting point) λ>(+7) =<< [1,2,3] -- nope λ>return (+7) =<< [1,2,3] -- nope λ>return (+7) >>= [1,2,3] -- nope λ>return [1,2,3] [1,2,3] it :: [Integer] -- just checking λ>[1,2,3] >>= (+7) -- nope λ>[1,2,3] >>= do (+7) -- nope. Error messages are talking about No instance for (Num [b0]) arising from the literal `1' so why is it looking inside the monad at one of the values and thinking that itself should be a list? λ>[1,2,3] >>= [(+7)] -- nope λ>[1,2,3] >>= (+7).return -- nope, but got *two* errors out of that one λ>[1,2,3] >>= liftM(+7) -- nope λ>[1,2,3] >>= liftM(+7) ::[Integer] -- nope λ>[1,2,3] >>= liftM(+7) ::Integer -- nope λ>[1,2,3] >>= liftM((+7) :: Integer -> Integer) -- nope λ>[[1,2,3]] >>= liftM((+7) :: Integer -> Integer) [8,9,10] it :: [Integer] Ah, I'm getting somewhere. But back to the question of why is the element of the list (nondeterminism monad) want its own element to be a list too? λ>return [1,2,3] >>= liftM((+7) :: Integer -> Integer) [8,9,10] it :: [Integer] Same thing. But the list is already a monad, not a bare (scalar) value, so what's going on? λ>[1,2,3] >>= (+7) -- nope λ>[1,2,3] >>= map(+7) -- nope λ>[1,2,3] >>= liftM(+7) -- nope Am I starting to repeat myself? λ>[1,2,3] >>= liftM(+7) ::[Integer] -- nope Give up for the evening. I wonder if that is a record for how many ways it can be incorrect? I'm frustrated, especially since the Applicative syntax worked so easily. But the referenced page and other texts casually say how they are interchangable. Urrrgh! Please enlighten? —John

Hi John!
2014-04-07 11:06 GMT+02:00 John M. Dlugosz
I think I was looking at the page http://learnyouahaskell.com/for-a-few-monads-more#state a few paragraphs under the H3 “The join function”. It mentions “…we wanted to combine several of them into one, be it with <*> or >>=,…”
Now I'm actually quite comfortable with Applicative syntax, and am preferring it in places where older texts and examples use monads or fmap etc. (I look forward to an updated standard where Monads are derived from Applicatives.)
(Aside: is there a "history" function in GHCi to show the last few commands I typed?)
So, I tried a GHCi example starting with:
λ>(+7) <$> [1,2,3]
λ>[(+7), (*2)] <*> [1,2,3]
no sweat. Now use >>= to do the same thing:
λ>[(+7), (*2)] >>= [1,2,3] -- nope (I'll spare the error messages, which inspired some of the other things to try, some of which were just to explore the errors themselves)
λ>[(+7), (*2)] <<= [1,2,3] -- nope
λ>[(+7), (*2)] =<< [1,2,3] -- nope
λ>[return (+7), return(*2)] =<< [1,2,3] -- nope
(Use a single function as a simpler starting point)
λ>(+7) =<< [1,2,3] -- nope
λ>return (+7) =<< [1,2,3] -- nope
λ>return (+7) >>= [1,2,3] -- nope
λ>return [1,2,3] [1,2,3] it :: [Integer] -- just checking
λ>[1,2,3] >>= (+7) -- nope λ>[1,2,3] >>= do (+7) -- nope. Error messages are talking about No instance for (Num [b0]) arising from the literal `1' so why is it looking inside the monad at one of the values and thinking that itself should be a list?
λ>[1,2,3] >>= [(+7)] -- nope
λ>[1,2,3] >>= (+7).return -- nope, but got *two* errors out of that one
You're close. It should be: [1,2,3] >>= return . (+7) Best, Karol

Hi John, for some versions you almost did it ;).
λ>return (+7) =<< [1,2,3]
return . (+7) =<< [1,2,3]
λ>[1,2,3] >>= (+7).return
[1,2,3] >>= return . (+7) It's really helpful to look at the types:
:t return (+7) return (+7) :: (Monad m, Num a) => m (a -> a) :t return . (+7) return . (+7) :: (Monad m, Num b) => b -> m b
Greetings, Daniel

John, This is one MAJOR hurdle for newcomers to get over and pretty much everyone stumbles and falls into typed combinator enlightenment. Eventually. Let's ask ghci what some of the types are: :t [1,2,3] [1,2,3] :: [Int] :t (+7) (+7) :: Int -> Int :t (<$>) (<$>) :: Functor f => (a -> b) -> f a -> f b So in ((+7) <$>) we have (<$>) :: Functor f => (a -> b) -> f a -> f b applied to (note the _type_ of the first argument: a -> b): (+7) :: Int -> Int Now the type variables a and b must match up, so we have a=b=Int. And now we have ((+7) <$>) :: Functor f => f Int - f Int Which is, in turn, applied to [1,2,3] :: [Int] The argument in ((+7) <$>) has type Functor f => f Int, whereas [1,2,3] is [Int], so what can f be? Answer: []. Yes, [] is a functor, the way Maybe and IO are functors. So f = []. It's unusual but only syntatically in the sense that Haskell says to write Maybe Int but rejects [] Int. You have to write [Int] to mean [] Int. We say that ((+7) <$>) :: Functor f => f Int - f Int is thus specialized to ((+7) <$>) :: [Int] -> [Int] which is why (+7) <$> [1,2,3] typechecks and runs as it should. If you run through the above against the rest of the list of things that do and don't work, I think you'll sew up typed combinators as a fine feather in your cap. Just remember that [] is a Functor and also an Applicative and a Monad. Trying different combinations is so much more satisfying if you lean on the types to lead you to greater good. -- Kim-Ee

On 4/8/2014 12:54 AM, Kim-Ee Yeoh wrote:
John,
This is one MAJOR hurdle for newcomers to get over and pretty much everyone stumbles and falls into typed combinator enlightenment. Eventually. ⋮ If you run through the above against the rest of the list of things that do and don't work, I think you'll sew up typed combinators as a fine feather in your cap. Just remember that [] is a Functor and also an Applicative and a Monad.
Thanks. I'll work through that again. —John

On Tue, Apr 08, 2014 at 12:54:17PM +0700, Kim-Ee Yeoh wrote:
Answer: []. Yes, [] is a functor, the way Maybe and IO are functors. So f = []. It's unusual but only syntatically in the sense that Haskell says to write Maybe Int but rejects [] Int. You have to write [Int] to mean [] Int.
This is not true. In fact, [] Int is perfectly valid Haskell syntax; it's just not very common. -Brent

On Mon, Apr 7, 2014 at 4:06 AM, John M. Dlugosz
(Aside: is there a "history" function in GHCi to show the last few commands I typed?)
:hist apparently only works at a breakpoint, but ghci does remember what
you typed, and you can look through it with up/down arrow. James
participants (6)
-
Brent Yorgey
-
Daniel Trstenjak
-
James Jones
-
John M. Dlugosz
-
Karol Samborski
-
Kim-Ee Yeoh