18

Haskell を使用して Web ページをスクレイピングし、結果をオブジェクトにコンパイルしようとしています。

なんらかの理由でページからすべての項目を取得できない場合は、ページの処理を中止して早期に戻りたいと考えています。

例えば:

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 ブロックを停止したり、他の部分が実行されないようにしたりしないことです。

これを行う正しい方法は何ですか?

4

3 に答える 3

18

returnreturnin haskell は他の言語と同じことをしません。代わりにreturn、モナド (この場合は ) に値を注入します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モナドが (例外を除いて) 制御効果を持たないことです。一方、多分モナドトランスフォーマーを使用できます

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 ()

警告: 上記のコードはいずれもテストされておらず、型チェックも行われていません!

于 2013-03-15T21:15:25.513 に答える
13

モナド変換子を使おう!

import Control.Monad.Trans.Class -- from transformers package
import Control.Error.Util        -- from errors package

scrapePage :: String -> IO ()
scrapePage url = maybeT (return ()) return $ do
  doc <- lift $ fromUrl url
  title <- liftM headMay $ lift . runX $ doc >>> css "head.title" >>> getText
  guard . not $ isNothing title
  date <- liftM headMay $ lift . runX $ doc >>> css "span.dateTime" ! "data-utc"
  guard . not $ isNothing date
  -- etc
  -- make page object and send it to db
  return ()

早期復帰時の戻り値の柔軟性を高めるには、throwError/ eitherT/EitherTの代わりにmzero/ maybeT/を使用しますMaybeT。(ただし、使用することはできませんguard。)

(おそらくheadZ代わりに使用headMayし、明示的なを捨てguardます。)

于 2013-03-15T21:14:29.640 に答える
1

私は Haskell を使ったことはありませんが、とても簡単に思えます。試してみてくださいwhen (isNothing date) $ exit ()。これも機能しない場合は、ステートメントが正しいことを確認してください。詳細については、この Web サイトも参照してください: Breaking From loop

于 2013-03-15T20:59:21.220 に答える