【问题标题】:using the Maybe monad with monadic actions将 Maybe monad 与 monadic 动作一起使用
【发布时间】:2015-05-08 12:35:40
【问题描述】:

例如,当我有一个 Maybe 值时,我想在它是 Just 时应用一些东西,或者如果它是 Nothing,就保留一个 Nothing,我有很多方法可以实现它在哈斯克尔。但是,当我想对其应用一元动作时,我没有找到一种简洁的方法。

在这段代码中,要获得d,我可以使用fmap。但我不能用它来获取c,因为它需要一个单子(在这种情况下为IO)操作才能应用于Maybe 中的值。

import Control.Applicative

main = do
    let x = Just "test.txt"
    let d = reverse <$> x -- good
    print d
    c <- case x of -- verbose
     Nothing -> return Nothing
     Just y -> Just <$> readFile y
    print c

这是一种可以做到的方式,但也太冗长了。

    c' <- maybe (return Nothing) (\a -> Just <$> readFile a) x
    print c'

我确定有更短的方法,我现在看不到它......

【问题讨论】:

标签: haskell


【解决方案1】:

您正在从Data.Traversable 中寻找traverse - 它有点像sequence/mapM 构造,应用于不是列表单子的单子(除了它应用于“可遍历”并且适用于事物比“monads”弱)。因此,对于您的特定情况,该功能只是:

traverseMaybe f Nothing = return Nothing
traverseMaybe f (Just x) = fmap Just (f x)

但是Data.Traversable 定义了一个更通用的类:

class (Functor t, Foldable t) => Traversable t where
    {-# MINIMAL traverse | sequenceA #-}

    -- | Map each element of a structure to an action, evaluate these
    -- these actions from left to right, and collect the results.
    -- actions from left to right, and collect the results. For a
    -- version that ignores the results see 'Data.Foldable.traverse_'.
    traverse :: Applicative f => (a -> f b) -> t a -> f (t b)
    traverse f = sequenceA . fmap f

    -- | Evaluate each action in the structure from left to right, and
    -- and collect the results. For a version that ignores the results
    -- see 'Data.Foldable.sequenceA_'.
    sequenceA :: Applicative f => t (f a) -> f (t a)
    sequenceA = traverse id

    -- | Map each element of a structure to a monadic action, evaluate
    -- these actions from left to right, and collect the results. For
    -- a version that ignores the results see 'Data.Foldable.mapM_'.
    mapM :: Monad m => (a -> m b) -> t a -> m (t b)
    mapM = traverse

    -- | Evaluate each monadic action in the structure from left to
    -- right, and collect the results. For a version that ignores the
    -- results see 'Data.Foldable.sequence_'.
    sequence :: Monad m => t (m a) -> m (t a)
    sequence = sequenceA

这也适用于非 monad 的应用函子,例如 ZipLists。

【讨论】:

  • 正是我想要的,感谢您的额外解释!
  • 现在正在查看。事实上,使用 GHC 4.10(基础 4.8)我什至可以使用通常的mapM,它不再必须在列表上工作,而是在任何Traversable 上工作,包括Maybe。并且traverse 使它甚至可以在Applicative 上工作,而不仅仅是Monad 函数。我想我现在明白了:-)
【解决方案2】:

traverse 在这里做你想做的事:

c' <- traverse readFile x
print c'

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-11-16
    • 2012-01-06
    • 2018-02-09
    • 1970-01-01
    • 2011-08-02
    • 1970-01-01
    • 2017-10-23
    • 1970-01-01
    相关资源
    最近更新 更多