在Haskell中合并/追加Justs

时间:2012-01-24 18:32:32

标签: haskell monads applicative maybe

我正在尝试做一些在Haskell中显而易见的事情,它从Just [1]Just [2]Just [1, 2]。但是我在网上找不到任何东西,因为我一直在寻找相关但无益的页面。那么,你是如何实现这一目标的呢?

4 个答案:

答案 0 :(得分:16)

您可以使用liftA2 (++)

liftA2 (++) :: Maybe [a] -> Maybe [a] -> Maybe [a]

liftA2只是将二进制函数提升为ApplicativeApplicative被设计用于在上下文中提升任意参数的函数,因此它们是完美的。在这种情况下,我们使用的ApplicativeMaybe。要了解其工作原理,我们可以查看定义:

liftA2 :: (Applicative f) => (a -> b -> c) -> f a -> f b -> f c
liftA2 f a b = f <$> a <*> b

(<$>)只是将纯值上的任何函数提升为f内的(a -> b) -> f a -> f bfmap。 (如果您熟悉Functor,则它只是Maybe的别名。)对于_ <$> Nothing = Nothing f <$> Just x = Just (f x)

(<*>)

f有点棘手:它将f内的函数应用于f (a -> b) -> f a -> f bMaybe内的值。对于Just f <*> Just x = Just (f x) _ <*> _ = Nothing

f <$> x

(事实上,pure f <*> xJust f <*> x相同,MaybeliftA2 (++)。)

因此,我们可以扩展liftA2 (++) a b = (++) <$> a <*> b -- expand (<$>) liftA2 (++) (Just xs) b = Just (xs ++) <*> b liftA2 (++) _ _ = Nothing -- expand (<*>) liftA2 (++) (Just xs) (Just ys) = Just (xs ++ ys) liftA2 (++) _ _ = Nothing

的定义
Applicative

实际上,我们可以使用这些运算符将任意个参数的函数提升到任何liftA2,只需遵循(++) <$> a <*> b的模式。这称为 applicative style ,在惯用的Haskell代码中非常常见。在这种情况下,如果ab已经是变量,那么通过撰写liftA2 (++)直接使用它可能更为惯用。 (另一方面,如果你部分应用它 - 比如说,将它传递给更高阶函数 - 那么Monad更可取。)

每个Applicative都是Applicative,因此,如果您发现自己试图将某个功能“提升”到某个环境中,{{1}}可能就是您正在寻找的内容。

答案 1 :(得分:3)

虽然@ ehird的答案很棒,但我会在表单中使用一个noobish解决方案:

mergeJust a b = do
    a' <- a
    b' <- b
    return (a' ++ b')

答案 2 :(得分:3)

要将解决方案扩展为Just列表,您可以使用

fmap join $ sequence [Just[1],Just[2],Just[3]]
-- Just [1,2,3]

答案 3 :(得分:1)

由于其他解决方案中没有提及,我会在这里说。在我看来,完成任务的最简单方法是使用<>中的mappend(或Data.Monoid)。

import Data.Monoid

Just [1,2] <> Just [7,8] == Just [1,2,7,8]

但请注意,与ehird的应用解决方案不同,此解决方案不会在Nothing值上发生短路。

Just [1,2] <> Nothing ---> Just [1,2]
--However
(++) <$> Just [1,2] <*> Nothing ---> Nothing