doブロックを早く返すにはどうすればよいですか? 質問する

doブロックを早く返すにはどうすればよいですか? 質問する

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

問題は、whendo ブロックを停止せず、他の部分の実行を妨げないことです。

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

ベストアンサー1

returnHaskellでは他の言語と同じことをしませんreturn。代わりに、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モナドが制御効果を持たないことです(例外を除く)。一方で、maybeモナドトランスフォーマーを使うこともできます。

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

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

おすすめ記事