不使用序列实现mapM

时间:2016-04-20 11:21:14

标签: haskell monads

我目前正在尝试解决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

有人可以给我一个提示,看哪个方向?

4 个答案:

答案 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]。