haskell - 如何让 do block 提前返回?

标签 haskell web-scraping monads

我正在尝试使用 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/

相关文章:

haskell - Haskell 数组创建中允许哪些递归调用?

google-maps - 从嵌入的谷歌地图中抓取数据

python - 如何将 Google Chrome 扩展与 Selenium 结合使用?

haskell - monad的类型构造函数和返回函数之间的区别(在Haskell中)

haskell - 解析为自由单子(monad)

haskell - 部分应用函数和柯里化(Currying),如何制作更好的代码而不是大量的 map ?

node.js - 使用 JSDOM 抓取网页(包括其子页面)

haskell - 在实践中使用单子(monad)、幺半群、仿函数和箭头

Haskell Monads 和 liftIO 我不明白

Haskell 冒号和点语法?