簡體   English   中英

IO和也許monad互動

[英]IO and Maybe monad interaction

我有以下代碼,但我覺得它太丑陋而且勢在必行。 有人會說它更具功能嗎? (我和MaybeT混淆但是無法使它工作)也歡迎應用答案。

getString :: IO String

pred :: String -> Bool

f :: String -> String

result :: IO (Maybe String)
result = do
  s <- getString
  if pred s
    then return $ Just $ f s
    else return Nothing

編輯:一個后續問題:如果pred和f都返回IO內的結果會怎么樣(我應該把它分成一個單獨的問題嗎?)

getString :: IO String

pred :: String -> IO Bool

f :: String -> IO String

result :: IO (Maybe String)
result = do
  s <- getString
  b <- pred s
  if b
    then Just <$> f s
    else return Nothing

我首先從IO monad中取出邏輯。 然后可以將您的函數寫為

result :: IO (Maybe String)
result = foo <$> getString

foo :: String -> Maybe String
foo s | pred s    = Just (f s)
      | otherwise = Nothing 

你可以使用一些奇特的組合器以不同的方式編寫foo ,但我不認為這是必要的。 最重要的是將您的邏輯從IO刪除,以便更容易測試。

這是一個很好的小組合:

ensure :: MonadPlus m => (a -> Bool) -> (a -> m a)
ensure p x = guard (p x) >> return x

現在我們可以編寫一個純函數來檢查你的謂詞並在適當時應用f

process :: String -> Maybe String
process = fmap f . ensure pred

將其提升為IO動作只是另一個fmap

result = fmap process getString

就個人而言,我可能會內聯process ,並以這種方式編寫:

result = fmap (fmap f . ensure pred) getString

...這是對正在發生的事情的一個相對清晰的描述。

代碼的明顯轉換是將return操作考慮return

result = do
  s <- getString
  return $ if pred s
           then Just (f s)
           else Nothing

這使得模式更加明顯:

result = liftM g getString
g s | pred s    = Just (f s)
    | otherwise = Nothing

通過從外部應用f ,我們可以使下一個模式顯而易見:

g s = liftM f $ if pred s then Just s else Nothing

這讓我們重新設置if塊:

g = liftM f . mfilter pred . return

總結一下:

result = liftM (liftM f . mfilter pred . return) getString
import Control.Monad

result = getString >>= (return . fmap f . (mfilter pred . Just) )

你不能輕易擺脫笨重的if-then-else ,但你可以逃脫冗余的returns

import Control.Monad

result :: IO (Maybe String)
result = go <$> getString where
  go s | pred s    = Just $ f s
       | otherwise = Nothing

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM