我有以下代码片段:
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'?我不认为有任何副作用,是吗?
另一个无助的解决方案:
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
哦,我的,那是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.