IO和也许monad互动

Ski*_*gys 16 haskell

我有以下代码,但我觉得它太丑陋而且势在必行.有人会说它更具功能吗?(我和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
Run Code Online (Sandbox Code Playgroud)

编辑:一个后续问题:如果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
Run Code Online (Sandbox Code Playgroud)

ham*_*mar 26

我首先从IOmonad中取出逻辑.然后可以将您的函数写为

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

foo :: String -> Maybe String
foo s | pred s    = Just (f s)
      | otherwise = Nothing 
Run Code Online (Sandbox Code Playgroud)

您可以foo使用一些奇特的组合器以不同的方式编写,但我不认为这是必要的.最重要的是让你的逻辑IO变得更容易测试.

  • +1不能否认从"IO"中获取逻辑比使用花哨的单行解决方案更重要. (6认同)

Dan*_*ner 10

这是一个很好的小组合:

ensure :: MonadPlus m => (a -> Bool) -> (a -> m a)
ensure p x = guard (p x) >> return x
Run Code Online (Sandbox Code Playgroud)

现在我们可以编写一个纯函数来检查你的谓词并f在适当的时候应用:

process :: String -> Maybe String
process = fmap f . ensure pred
Run Code Online (Sandbox Code Playgroud)

将此提升为一个IO动作只是另一个fmap:

result = fmap process getString
Run Code Online (Sandbox Code Playgroud)

就个人而言,我可能会内联process,并以这种方式写:

result = fmap (fmap f . ensure pred) getString
Run Code Online (Sandbox Code Playgroud)

...这是对正在发生的事情的一个相对清晰的描述.


JB.*_*JB. 9

代码的明显转换是对return操作进行分析:

result = do
  s <- getString
  return $ if pred s
           then Just (f s)
           else Nothing
Run Code Online (Sandbox Code Playgroud)

这使得模式更加明显:

result = liftM g getString
g s | pred s    = Just (f s)
    | otherwise = Nothing
Run Code Online (Sandbox Code Playgroud)

通过f从外部申请,我们可以使下一个模式显而易见:

g s = liftM f $ if pred s then Just s else Nothing
Run Code Online (Sandbox Code Playgroud)

这让我们重新阻止了这个if块:

g = liftM f . mfilter pred . return
Run Code Online (Sandbox Code Playgroud)

总结一下:

result = liftM (liftM f . mfilter pred . return) getString
Run Code Online (Sandbox Code Playgroud)


lef*_*out 5

import Control.Monad

result = getString >>= (return . fmap f . (mfilter pred . Just) )
Run Code Online (Sandbox Code Playgroud)

  • `result =(f <$> mfilter pred.只是)<$> getString` (2认同)