如何在Haskell中编写常见的"if"分支

ond*_*dra 5 haskell

我有以下代码片段:

srcaddr <- getIfaceAddr iface >>= inet_ntoa . fromJust 
dstaddr <- getDestAddr iface >>= inet_ntoa . fromJust 
-- I want to perform actions only if neither getIfaceAddr 
-- nor getDestAddr returned Nothing
action1 srcaddr dstaddr
action2 srcaddr dstaddr
action3 srcaddr dstaddr

getIfaceAddr :: String -> IO (Maybe HostAddress)
getDestAddr :: String -> IO (Maybe HostAddress)
Run Code Online (Sandbox Code Playgroud)

如何在'漂亮的Haskell'中编写这段代码?我在考虑MaybeT monad,但不知何故无法使它工作.我试图做一些"提升",但无法将这些类型组合在一起.我可以更改getIfaceAddr/getDestAddr的签名.

作为旁注:为什么inet_ntoa'HostAddress-> IO String'?我不认为有任何副作用,是吗?

scl*_*clv 6

另一个无助的解决方案:

msrcaddr <- getIfaceAddr iface >>= traverse inet_ntoa
mdstaddr <- getDestAddr iface >>= traverse inet_ntoa
case liftM2 (,) msrcaddr mdstaddr of
   Just (srcaddr,dstaddr) ->
      action1 srcaddr dstaddr
      action2 srcaddr dstaddr
      action3 srcaddr dstaddr
   Nothing -> return ()
Run Code Online (Sandbox Code Playgroud)

maybe如果您愿意,也可以用a替换表壳.或者你可以直接通过模式匹配来避免liftM2.

编辑:这里是Traversable文档的链接,这是一个被忽视但经常不可或缺的类型类:http://haskell.org/ghc/docs/6.12.2/html/libraries/base-4.2.0.1/Data-Traversable.html


luq*_*qui 5

哦,我的,那是fromJust什么?如果getIfaceAddr返回Nothing,此代码将使程序崩溃.

MaybeT解决方案是这样的:

srcaddr <- lift . inet_ntoa =<< MaybeT (getIfaceAddr iface)
dstaddr <- lift . inet_ntoa =<< MaybeT (getDestAddr iface)
lift $ do
    action1 srcaddr dstaddr
    ...
Run Code Online (Sandbox Code Playgroud)

第一行的类型如下所示:

getIfaceAddr iface          :: IO (Maybe HostAddress)
MaybeT (getIfaceAddr iface) :: MaybeT IO HostAddress
inet_ntoa                   :: HostAddress -> IO String
lift . inet_ntoa            :: HostAddress -> MaybeT IO String
lift . inet_ntoa =<< MaybeT (getIfaceAddr iface)
                            :: MaybeT IO String
Run Code Online (Sandbox Code Playgroud)

请记住,您的代码将具有类型MaybeT IO something,因此您必须在runMaybeT将其IO绑定到之前将其恢复main.