Reputation: 34099
I have following function:
meh :: (Functor m, Monad m) => [a] -> (a -> m b) -> m [b]
meh [] _ = return []
meh (x:xs) f = do
x' <- f x
fmap ((:) x') (meh xs f)
then I try it out in prelude as follow and I've got:
*ExerciseMonad Control.Monad> meh [3,4,5] (\x -> Just x)
Just [3,4,5]
But I do expect [Just 3, Just 4, Just 5]
.
To find out, what went wrong, I did substitution:
meh [3,4,5] (\x -> Just x) = Just [3,4,5]
meh (3:[4,5])] (\x -> Just x) =
Just 3 <- (\3 -> Just 3)
fmap ((:) (Just 3)) (meh [4,5] (\x -> Just x))
meh (4:[5])] (\x -> Just x) =
Just 4 <- (\4 -> Just 4)
fmap ((:) (Just 4)) (meh [5] (\x -> Just x))
meh ([5])] (\x -> Just x) =
Just 5 <- (\5 -> Just 5]
fmap ((:) (Just 5)) (meh [] (\x -> Just x))
meh [] _ = return []
--all the way back
meh ([5])] (\x -> Just x) = fmap ((:) (Just 5)) []
meh (4:[5])] (\x -> Just x) = fmap ((:) (Just 4)) [Just 5] <- result [Just 4, Just 5]
meh (3:[4,5])] (\x -> Just x) = fmap ((:) (Just 3)) [Just 4, Just 5] <- result [Just 4, Just 5]
meh [3,4,5] (\x -> Just x) = [Just 3,Just 4, Just 5]
As you can see, the substitution does not match to the right result:
Just [3,4,5] != [Just 3,Just 4, Just 5]
My question, what did I wrong with the substitution? That I've got the wrong result?
Upvotes: 1
Views: 49
Reputation: 42756
As I commented before your type signature is wrong:
If you check the type for [Just 1, Just 2, ...]
would be like [m b]
not m []
.
Also, you cant simplify your function to:
meh :: (Functor m, Monad m) => [a] -> (a -> m b) -> [m b]
meh l f = fmap f l
Here you have a life example
Your substitution is wrong on this step:
x' <- f x
Since you are working inside a monad you are binding (with <-
) to x'
the Value inside
the monad (Just
in this case) so 'x'' will be 3
(4, 5, ...) not Just 3
Upvotes: 0
Reputation: 15045
According to the type, everything works fine
meh :: (Functor m, Monad m) => [a] -> (a -> m b) -> m [b]
If you're expecting [Just 3, Just 4, Just 5]
you might need something like:
meh :: (Functor m, Monad m) => [a] -> (a -> m b) -> [m b]
Or just
meh :: (Functor m) => [a] -> (a -> m b) -> [m b]
Because you don't need the monad instance if you're not going to join values.
meh' :: (Functor m, Monad m) => [a] -> (a -> m b) -> [m b]
meh' [] _ = []
meh' (x:xs) f =
(f x) : (meh' xs f)
Calling meh' [3,4,5] Just
returns [Just 3, Just 4, Just 5]
Calling meh [3,4,5] Just
returns Just [3,4,5]
Talking about a substitution (starting from the empty list):
meh [] _ = Just []
, because meh [] _ = return []
returns an empty list wrapped into a monadic structure (in this case Maybe
monad)
meh (5:[]) (\x -> Just x) = do
x' <- (\x -> Just x) 5
fmap ((:) x') (meh [] (\x -> Just x))
In this step x' <- (x -> Just x) 5
binds x'
to 5
. That's why meh [5] Just
transforms into fmap ((:) 5) (Just [])
that equals Just [5]
, rather than fmap ((:) (Just 5)) []
which indeed equals [Just 5]
Upvotes: 2