[英]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.