2017-02-06 84 views
1

有功能與類似簽名:如何鏈 - > IO(M B)功能

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

如何把它們連在

a -> IO (m d) 

實際應用:假設有一組REST端點。每個返回值和下一個值都要求前面返回的值作爲參數。從終端獲取

因此函數是這樣的:

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

您正在尋找Kliesli組合物'(> =>)'檢查這裏的http:// hackage .haskell.org/package/base-4.9.1.0/docs/Control-Monad.html#v:-62--61--62- – zeronone

+1

此外'IO(也許a)〜MaybeT IO a'和'MaybeT'是在http://hackage.haskell.org/package/transformers-0.5.2.0/docs/Control-Monad-Trans-Maybe.html#v:MaybeT – zeronone

回答

6

有與類似的簽名功能:

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

如何把它們連在

a -> IO (m d) 

屬屬l,你可能無法。例如,如果mConst,我不確定問這甚至是有道理的。一般而言,您可能預期mMonad。但是,請注意,即使m a 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) 

這仍然看起來有點難看。要做的事情可能是重構您的rest1,rest2rest3函數。正如已經在評論MaybeT IO a中指出的那樣,可以將其轉換爲IO (Maybe a)(其實這正是runMaybeTMaybeT所做的)。

import 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 
+0

中定義在重構之後,重新調整「rest」函數是否有意義,重新奪回風味原有的功能?例如,'rest1 :: MonadTrans mt => Value1 - > mt IO Value2'? – chepner

+0

@chepner我肯定會說是的;儘管我不確定你的特定類型是否合理。像'rest1 ::(MonadIO m,MonadPlus m)=> Value1 - > m Value2'會表示'rest1'可能會做一些IO('MonadIO')並且可能不會成功('MonadPlus')。 –

2

如果m具有Traversable一個實例(Maybe有一個)這裏是另一種選擇:

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 
+0

看起來你不需要'liftIO',而>> >> = return。 join'是'fmap join'。 –

+0

是的,你是對的。 –

+0

爲帶有>> =返回的部分。加入'我想分開最後一步。所以如果有人想在這個例子中添加更多的步驟(即'd - > IO(m e)'),他們只需要用>> >> =遍歷fd來添加另一行。加入'在最後一行之前。 –

相關問題