2013-08-18 10 views
5

私はParsecを学びようとしており、簡単な電子メールアドレスを解析しようとしています。 次のコードを試しました。私の予想される出力は、電子メールアドレス全体が文字列として出力されます。しかし、私がコードを実行すると、私は ".com"しか得ることができませんsomeneは何が起こっているか教えてください?ハスケルParsecの惨事

{-# LANGUAGE NoMonomorphismRestriction #-} 

import Text.Parsec 
import Control.Applicative hiding ((<|>)) 

email = many1 alphaNum 
    *> char '@' 
    *> many1 alphaNum 
    *> string ".com" 

emailstr = parse email "" "[email protected]" 

答えて

12

*>の型シグネチャは、パーサからの結果を返し、パーサからの結果を捨て言います。したがって、emailは、シーケンス内の最終パーサーからの結果のみを返します。

は何あなたはおそらく欲しいのはこれが4つのパーサーを実行し、stitchへの引数としてそれぞれの結果を渡すより

email = 
    stitch 
    <$> many1 alphaNum 
    <*> char '@' 
    <*> many1 alphaNum 
    <*> string ".com" 

のようなものです。あなたはstitchに適した実装を記述する場合:

stitch a b c d = a ++ [b] ++ C++ d 

はその後、あなたの文字列が返されます。この時点で、あなたはまた、データ構造や何かの別々のフィールドにユーザー名とドメインを置くことができ

お知らせ:

data Email = Email {username, domain :: String} 

email = 
    Email 
    <$> many1 alphaNum 
    <* char '@' 
    <*> ((++) <$> many1 alphaNum <*> string ".com") 

は、今すぐあなたのパーサは単なる文字列ではなくEmail構造体を返します。それはあなたの後ろではないかもしれませんが、より洗練されたパーサを書く方法を示しています。

これはすべて一般的に良いスタイルと見なされるParsecへのApplicativeインターフェイスを使用しています。 Parsecのを使用する方法がMonadインタフェースです:

email = do 
    a <- many1 alphaNum 
    b <- char '@' 
    c <- many1 alphaNum 
    d <- string ".com" 
    return (a ++ [b] ++ C++ d) 
+0

は、これは言ったタスクを達成するための慣用的な方法は何ですか?本番環境でコードを使用することはありません。私は単にparsecを勉強しようとしています。 – Jay

+0

どちらも慣用です – nponeccop