2015-11-08 87 views
6

我想知道是否有一種習慣方式來編寫類似於IO Monad中命令式語言中的鏈式if/else語句的控制代碼。在IO Monad中鏈接if/else腳本

在像Python語言

所以,我通常會正確的是這樣的:

if οs.path.isdir(fname): 
    # do whatever 
elif os.path.isfile(fname): 
    # ... 
else: 
    # ... 

最好我能想出在Haskell如下:

isf <- doesFileExist path 
isd <- if isf then return False else doesDirectoryExist path 
case (isf, isd) of 
    (True, _)  -> return ... 
    (_,  True) -> return ... 
    _    -> return ... 

這是不一樣好,我想知道是否有更好的方法來寫這種事情。

此外,爲了驗證我的理解:如果您不想始終執行這兩個操作,則IO Monad的情況下需要if isf部分isd <- ...。我的猜測是,在其他單子(懶惰單子?),這將不會被需要,因爲isd將被評估懶惰。

編輯

基於第一意見,我結束了以下內容:

firstMatchM :: (Monad m) => a -> [(a -> m Bool, b)] -> b -> m b 
firstMatchM arg [] def = return def 
firstMatchM arg ((check,x):xs) def = do 
    t <- check arg 
    if t then return x else firstMatchM arg xs def 

doFirstM :: (Monad m) => a -> [(a -> m Bool, a -> m b)] -> (a -> m b) -> m b 
doFirstM arg acts def = do 
    fm <- firstMatchM arg acts def 
    fm arg 

handlePath2 path = doFirstM path 
    [(\p -> doesFileExist p, 
     \p -> return "file" 
    ),(\p -> doesDirectoryExist p, 
     \p -> return "dir" 
    )] $ \p -> return "Error" 

這類似於@卡的第二個建議,有點我喜歡ifM,因爲它更接近命令版本。

+0

但即使在Python,你應該重構這些;) – Carsten

+0

OK,我會咬,怎麼樣? :) – ynimous

+0

那麼,你可以做一些事情,比如建立一個動作列表,使用'foldM'或'forM'等東西來獲得你想要的結果。這會推廣到任何數量的elif,儘管只有3個案例會很麻煩。在python中也是如此:'test,test_and_actions中的動作:if test(input):action(input)'。 – Bakuriu

回答

4

如果我們不想涉及單子變壓器,一個基本的選項是滾動自己的單子if

ifM :: Monad m => m Bool -> m a -> m a -> m a 
ifM act t e = do 
    b <- act 
    if b then t else e 

然後代碼結構是一個類似於在命令式語言:

test :: IO String 
test = ifM anAction (do 
      putStrLn "branch a" 
      return "a") 
     $ ifM otherAction (do 
      putStrLn "branch b" 
      return "b") 
     $ return "none" 

其中anAction, otherAction :: IO Bool

另外,使用類似

ifChain :: [(IO Bool, IO a)] -> IO a -> IO a 
ifChain [] e = e 
ifChain ((g, a) : acts) e = do 
    b <- g 
    if b then a else ifChain acts e 
+0

@Bakuriu對。 – chi

+0

我覺得我更喜歡'ifM'。你會怎麼做一元變壓器? – ynimous

+0

@ynimous我試過monad變形金剛('MaybeT'),但我不喜歡這個結果:太多的'lift'和樣板代碼。也許別人可以發佈一些實際可讀的代碼。 – chi