有关monadic值的fmap有什么相似之处?

Ste*_*eve 10 haskell

这对Haskell专业人员来说应该很容易..

我有一个可能值,

> let a = Just 5
Run Code Online (Sandbox Code Playgroud)

我可以打印出来:

> print a
Just 5
Run Code Online (Sandbox Code Playgroud)

但我想将一个I/O动作应用于Maybe的内部.我没有使用的唯一方法是找出如何做到这case一点:

> maybe (return ()) print a
5
Run Code Online (Sandbox Code Playgroud)

但是,这似乎太冗长了.首先,return ()特定于I/O monad,所以我必须为每个我想尝试这个技巧的monad提出一个不同的"零".

我想基本上将I/O操作(打印)映射到Maybe值,如果是Just,则打印它,如果是,则不执行任何操作Nothing.我想以某种方式表达它,

> fmap print a
Run Code Online (Sandbox Code Playgroud)

但这不起作用,因为print是IO动作:

No instance for (Show (IO ()))
Run Code Online (Sandbox Code Playgroud)

我试过Applicative,但无法弄清楚是否有办法表达它:

> print <$> a
No instance for (Show (IO ()))
Run Code Online (Sandbox Code Playgroud)

显然我对Monads-inside-monads有点困惑..谁能告诉我最简洁的表达方式的正确方法?

谢谢.

scl*_*clv 23

pelotom的答案是直截了当的.但不是有趣的!sequence是Haskell函数,人们可以将其视为在列表和monad之间翻转类型构造函数的顺序.

sequence :: (Monad m) => [m a] -> m [a]

现在你想要的是,在a Maybe和monad 之间翻转类型构造函数的顺序.Data.Traversable只输出一个sequence具有该容量的函数!

Data.Traversable.sequence :: (Traversable t, Monad m) => t (m a) -> m (t a)

这可以Maybe (IO ()) -> IO (Maybe ())在你的例子中特别喜欢.

因此:

Prelude Data.Traversable> Data.Traversable.sequence (fmap print $ Nothing)
Nothing

Prelude Data.Traversable> Data.Traversable.sequence (fmap print $ Just 123)
123
Just ()
Run Code Online (Sandbox Code Playgroud)

请注意,还有一个sequenceA稍微更通用的功能,不仅适用于Monads,还适用于所有Applicatives.

那么为什么要用这种方法?对于Maybe明确区分它的方法很好.但是更大的数据结构Map呢?例如?在这种情况下,traverse,sequenceA和朋友Data.Traversable才能真正派上用场.

编辑:正如Ed'ka所说,traverse :: Applicative f => (a -> f b) -> t a -> f (t b)所以人们可以写traverse print $ Just 123.

  • 您可以使用相同结果的`traverse print $ Just 123` (9认同)
  • @Daniel Velkov,http://hackage.haskell.org/packages/archive/base/latest/doc/html/Data-Foldable.html#v:traverse_因为它丢弃了结果(Traversable的形状)它只需要是可折叠的 (2认同)

Tom*_*ett 16

首先,return()是特定于I/O monad的,所以我必须为每个我想尝试这个技巧的monad提出一个不同的"零".

return () 实际上是非常通用的,从它的类型可以看出:

Prelude> :t return ()
return () :: (Monad m) => m ()
Run Code Online (Sandbox Code Playgroud)

我认为这种maybe (return ()) print a做法没有错.