【发布时间】:2012-02-18 00:14:42
【问题描述】:
我正在尝试做在 Haskell 中必须非常明显的事情,即从 Just [1] 和 Just [2] 到 Just [1, 2]。但是我在网上找不到任何东西,因为我一直在寻找相关但无用的页面。那么,您是如何实现这一目标的呢?
【问题讨论】:
标签: haskell monads applicative maybe
我正在尝试做在 Haskell 中必须非常明显的事情,即从 Just [1] 和 Just [2] 到 Just [1, 2]。但是我在网上找不到任何东西,因为我一直在寻找相关但无用的页面。那么,您是如何实现这一目标的呢?
【问题讨论】:
标签: haskell monads applicative maybe
你可以使用liftA2 (++):
liftA2 (++) :: Maybe [a] -> Maybe [a] -> Maybe [a]
liftA2 只是将二进制函数提升为Applicative。 Applicatives 是为在上下文中提升任意参数的函数而设计的,因此它们非常适合这一点。在这种情况下,我们使用的Applicative 是Maybe。要了解它是如何工作的,我们可以查看定义:
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 b。 (这只是fmap 的别名,如果您熟悉Functors。)对于Maybe:
_ <$> Nothing = Nothing
f <$> Just x = Just (f x)
(<*>) 有点棘手:它将f 中的函数应用于f 中的值:f (a -> b) -> f a -> f b。对于Maybe:
Just f <*> Just x = Just (f x)
_ <*> _ = Nothing
(其实f <$> x和pure f <*> x是一回事,也就是Just f <*> x代表Maybe。)
所以,我们可以扩展liftA2 (++)的定义:
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的模式即可。这称为应用风格,在惯用的 Haskell 代码中很常见。在这种情况下,如果a 和b 已经是变量,那么直接通过编写(++) <$> a <*> b 来使用它可能会更加地道。 (另一方面,如果您部分应用它——例如,将它传递给高阶函数——那么liftA2 (++) 更可取。)
每个Monad 都是Applicative,所以如果你发现自己试图将一个函数“提升”到上下文中,Applicative 可能就是你要找的。p>
【讨论】:
[2] 和 Just [3] -> Just [2, 3] 的等价物吗? :)
(2 :) <$> Just [3]
(xs ++) <$> mys 可用于在mys :: Maybe [a] 中添加任何xs :: [a]。
虽然@ehird 的回答很棒,但我会以如下形式使用一个笨拙的解决方案:
mergeJust a b = do
a' <- a
b' <- b
return (a' ++ b')
【讨论】:
[a' ++ b' | a' <- a, b' <- b]
要将解决方案扩展到Justs 列表,您可以使用
fmap join $ sequence [Just[1],Just[2],Just[3]]
-- Just [1,2,3]
【讨论】:
由于其他解决方案中没有提到,我就在这里说一下。在我看来,完成任务的最简单方法是使用来自Data.Monoid 的<>(或mappend)。
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
【讨论】: