2013-03-15 10 views
13

私は、Haskellを使用してWebページをスクレープし、結果をオブジェクトにコンパイルしようとしています。doブロックリターンを早期に行うにはどうすればよいですか?

何らかの理由でページからすべてのアイテムを取得できない場合は、ページの処理を早めにやり直してください。例えば

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を行うブロックを停止または実行中の他の部分を保持しないです。

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

+1

これは必要なのですか? http://www.haskellforall.com/2012/07/breaking-from-loop.html –

答えて

14

return。代わりに、returnが行うのは、モナドに値を注入することです(この場合はIO)。あなたはオプション

最も簡単なのカップルが

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

別のオプションは、IOモナドが持っていないされていることを、ここで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() 

一般的な問題を使用する場合に使用することである必要がありコントロール効果(例外を除く)。上記のコードのいずれも行われていない:あなたは本当にあなたが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() 

警告を使用する必要が本格的な制御効果を取得したい場合一方、あなたは多分モナド変圧器

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

を使用することができますテストしたり、タイプチェックしたりすることもできます。

+0

2番目のアプローチは私のためにうまくいった。私はあなたがいないと思います '(条件)$ do' コンパイルするには( '$'に気づく) – kunigami

2

私はハスケルとは仕事をしたことがありませんが、簡単です。試してくださいwhen (isNothing date) $ exit()。これもうまくいかない場合は、文が正しいことを確認してください。さらに詳しい情報は、このウェブサイトをご覧ください:Breaking From loop

+4

いいリンクですが、この例では 'exit'が定義されており、組み込み関数ではありません。その記事の解決策は@ dave4420の解決策と同じです:モナド変圧器。 – luqui

12

モナドトランスを使用してください!あなたが早期復帰、throwError/eitherT/EitherT代わりのmzero/maybeT/MaybeTを使用して、戻り値をより柔軟にするために

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

。 (そして、あなたがguardを使用することはできませんが。)

(おそらく代わりheadMayheadZを使用して明示的guardを捨てる。)ほかの言語でのreturnと同じことをしないHaskellでは

+1

'Control.Error.Util'は何のために必要ですか? –

+1

@Joehillen 'maybeT'。 – dave4420

関連する問題