我目前正在尝试解决20 Intermediate Haskell Excercises练习,并且在没有使用mapM
的情况下试图实施moppy
(练习中为sequence
)。
我只需应用[m b]
即可生成fmap
,但我不知道如何继续:
moppy :: [a] -> (a -> m b) -> m [b]
moppy la f = furry' f la -- how do I transform [m b] to m [b] without sequence
有人可以给我一个提示,看哪个方向?
答案 0 :(得分:8)
在现代时代,正如本杰明霍奇森所提到的,我们应该将Applicative
用于此特定目的:
myMapM :: Applicative f
=> (a -> f b) -> [a] -> f [b]
我们希望myMapM f []
为pure []
(我们无法获得任何b
!),所以
myMapM f [] = pure []
现在我们了解问题的核心,找出递归步骤。我们希望myMapM f (x : xs)
执行f x
,执行myMapM f xs
,然后合并结果。所以
myMapM f [] = pure []
myMapM f (x : xs) = (:) <$> f x <*> myMapM f xs
在使用列表做一些不错且经常的事情时,我们常常只能使用foldr
:
myMapM f = foldr go (pure []) where
go x r = (:) <$> f x <*> r
答案 1 :(得分:3)
嗯,我不知道如何在没有太多剧透的情况下做到这一点 - 所以在这里你会得到一个非常基本/递归的定义:
moppy :: Monad m => [a] -> (a -> m b) -> m [b]
moppy [] _ = return []
moppy (x:xs) f = do
y <- f x
ys <- moppy xs f
return (y:ys)
它应该是相当不言自明的 - 请注意你需要Monad m
约束(我认为无论如何你都想要它,因为没有它它会变得不可能;)
答案 2 :(得分:2)
当您开始使用mapM
和>>=
实施return
时,这可能会有所帮助。你最终会得到类似的东西:
mapM' :: Monad m => (a -> m b) -> [a] -> m [b]
mapM' _ [] = return []
mapM' f (x:xs) = f x >>=
\y -> mapM' f xs >>=
\ys -> return (y:ys)
这种方式可以像前面提到的海报一样给出答案。您需要做的就是更改参数的顺序:
moppy :: (Misty m) => [a] -> (a -> m b) -> m [b]
moppy [] _ = unicorn []
moppy (x:xs) f = banana (\y -> banana (\ys -> unicorn (y:ys)) (moppy xs f)) (f x)
或者:
moppy :: (Misty m) => [a] -> (a -> m b) -> m [b]
moppy [] _ = unicorn []
moppy (x:xs) f = (\y -> (\ys -> unicorn (y:ys)) `banana` moppy xs f) `banana` f x
或者:
moppy :: (Misty m) => [a] -> (a -> m b) -> m [b]
moppy [] _ = unicorn []
moppy (x:xs) f = let g y = let h ys = unicorn (y : ys)
in h `banana` moppy xs f
in g `banana` f x
答案 3 :(得分:1)
执行此实现:
moppy :: Monad m => (a -> m b) -> [a] -> m [b]
moppy f xs = foldr g n xs
where
n = return []
g x mys = do {
y <- f x ;
ys <- mys ;
return (y:ys) }
({mys :: m [b]
因为foldr g n (x:xs) = g x (foldr g n xs)
。)
(摘自C9讲座:RalfLämmel-Going Bananas [8:06 min-youtube]。