如何链接 - > IO(m b)功能

时间:2017-02-06 08:20:18

标签: haskell types monads

有些签名的功能如下:

a -> IO (m b)
b -> IO (m c)
c -> IO (m d)

如何在

中链接它们
a -> IO (m d)

实际应用:说有一组REST端点。每个返回值和下一个值都需要将previous返回的值作为参数。

因此从端点获取的函数如下:

Value1 -> IO (Maybe Value2)
Value2 -> IO (Maybe Value3)
Value3 -> IO (Maybe Value4)

2 个答案:

答案 0 :(得分:6)

  

有些签名的功能如下:

a -> IO (m b)
b -> IO (m c)
c -> IO (m d)
     

如何在

中链接它们
a -> IO (m d)

一般情况下,您可能无法做到。例如,如果mConst,我不确定这是否有意义。通常,您可能希望mMonad。但请注意,即使m Monad,其IO的合成也可能不是(see this)。

Value1 -> IO (Maybe Value2)
Value2 -> IO (Maybe Value3)
Value3 -> IO (Maybe Value4)
啊,现在你在说话!您在这里寻找的抽象是MaybeT和Kleisli组合(>=>)。然后,例如,

import Control.Monad ((>=>))
import Control.Monad.Trans.Maybe (MaybeT(..))

rest1 :: Value1 -> IO (Maybe Value2)
rest2 :: Value2 -> IO (Maybe Value3)
rest3 :: Value3 -> IO (Maybe Value4)

rest4 :: Value1 -> IO (Maybe Value4)
rest4 x = runMaybeT ((MaybeT . rest1 >=> MaybeT . rest2 >=> MaybeT . rest3) x)

那仍然看起来有点难看。要做的事情可能是重构您的rest1rest2rest3函数。正如评论中指出的那样MaybeT IO a可以转换为IO (Maybe a)和从runMaybeT转换(实际上这正是MaybeTimport Control.Monad ((>=>)) import Control.Monad.Trans.Maybe (MaybeT(..)) rest1 :: Value1 -> MaybeT IO Value2 rest2 :: Value2 -> MaybeT IO Value3 rest3 :: Value3 -> MaybeT IO Value4 rest4 :: Value1 -> MaybeT IO Value4 rest4 = rest1 >=> rest2 >=> rest3 所做的。)

{{1}}

答案 1 :(得分:2)

如果m的实例为TraversableMaybe有一个),则这是另一种选择:

import           Control.Monad (join)

f :: (Traversable m, Monad m)
  => (a -> IO (m b))
  -> (b -> IO (m c))
  -> (c -> IO (m d))
  -> a
  -> IO (m d)
f fa fb fc a = fa a
           >>= traverse fb
           >>= fmap join . traverse fc . join