我正在尝试使用 Haskell 抓取网页并将结果编译到一个对象中。
如果出于某种原因,我无法从页面获取所有项目,我想停止尝试处理页面并提前返回。
例如:
scrapePage :: String -> IO ()
scrapePage url = do
doc <- fromUrl url
title <- liftM headMay $ runX $ doc >>> css "head.title" >>> getText
when (isNothing title) (return ())
date <- liftM headMay $ runX $ doc >>> css "span.dateTime" ! "data-utc"
when (isNothing date) (return ())
-- etc
-- make page object and send it to db
return ()
问题是 when
不会停止 do block 或阻止其他部分执行。
执行此操作的正确方法是什么?
最佳答案
haskell 中的
return
与其他语言中的 return
的作用不同。相反,return
的作用是将一个值注入(inject)到 monad 中(在本例中为 IO
)。您有几个选择
最简单的是使用if
scrapePage :: String -> IO ()
scrapePage url = do
doc <- fromUrl url
title <- liftM headMay $ runX $ doc >>> css "head.title" >>> getText
if (isNothing title) then return () else do
date <- liftM headMay $ runX $ doc >>> css "span.dateTime" ! "data-utc"
if (isNothing date) then return () else do
-- etc
-- make page object and send it to db
return ()
另一种选择是使用unless
scrapePage url = do
doc <- fromUrl url
title <- liftM headMay $ runX $ doc >>> css "head.title" >>> getText
unless (isNothing title) do
date <- liftM headMay $ runX $ doc >>> css "span.dateTime" ! "data-utc"
unless (isNothing date) do
-- etc
-- make page object and send it to db
return ()
这里的普遍问题是IO
monad没有控制效果(异常(exception)情况除外)。另一方面,您可以使用 Maybe monad 转换器
scrapePage url = liftM (maybe () id) . runMaybeT $ do
doc <- liftIO $ fromUrl url
title <- liftIO $ liftM headMay $ runX $ doc >>> css "head.title" >>> getText
guard (isJust title)
date <- liftIO $ liftM headMay $ runX $ doc >>> css "span.dateTime" ! "data-utc"
guard (isJust date)
-- etc
-- make page object and send it to db
return ()
如果你真的想获得完整的控制效果,你需要使用ContT
scrapePage :: String -> IO ()
scrapePage url = runContT return $ do
doc <- fromUrl url
title <- liftM headMay $ runX $ doc >>> css "head.title" >>> getText
when (isNothing title) $ callCC ($ ())
date <- liftM headMay $ runX $ doc >>> css "span.dateTime" ! "data-utc"
when (isNothing date) $ callCC ($ ())
-- etc
-- make page object and send it to db
return ()
警告:以上代码均未经过测试,甚至没有进行类型检查!
关于haskell - 如何让 do block 提前返回?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15441956/