5

宿題の一部であるParsecライブラリの使い方を学ぶ。

編集:他のライブラリを使用する提案は大歓迎です。要点は構文解析です。

私が欲しいのは、大文字ですべての単語を抽出し、任意の文から4つのコンパスの方向を抽出することです。例:「ベルギーは完全にオランダの南にあります。」「BelgiumsouthHolland」を見つけて返す必要があります。

私が理解できないのは、コンパスの方向ではない入力を無視(食べる)する方法です。私はの線に沿って何かを見つけようとしていました

'many (not compassDirection >> space)'

しかし、g(h)oogleは私を助けていません。

次のコードは明らかに「多くの」関数に固執しています。

readExpr :: String -> String
readExpr input = case parse (parseLine) "" input of
    Left err -> "No match: " ++ show err
    Right val -> "Found: " ++ showVal val

parseLine :: Parser GraphValue
parseLine = do
            x <- parseCountry
            space
            many ( some (noneOf " ") >> space )
            y <- parseCompass
            space
            many ( some (noneOf " ") >> space )
            z <- parseCountry
            return $ Direction [x,y,z]

compassDirection :: Parser String
compassDirection = string "north" <|>
                   string "south" <|>
                   string "east" <|>
                   string "west"

parseCountry :: Parser GraphValue
parseCountry = do 
                c <- upper 
                x <- many (lower)
                return $ Country (c:x)

parseCompass :: Parser GraphValue
parseCompass = do 
                x <- compassDirection
                return $ Compass x
4

3 に答える 3

4

これは宿題であり、OPは「重要なことは構文解析である」と言ったので、詳細には立ち入りません。


この問題を解決する方法:

  • 入力をトークン化します。それを言葉に分けてください。これにより、実際の解析ステップで、トークンの定義(つまり、「%#@ [は単語の一部ですか?」)や空白を気にする必要がなくなります。wordsこれは、トークン化にParsecを使用するのと同じくらい簡単な場合もあれば、使用する場合もあります。その後、あなたは持っているでしょう[Token](または[String]あなたが望むなら)。

  • コンパス方向のパーサー。あなたはすでにこれを持っています(良い仕事です)が、入力が[String]の代わりである場合は少し変更する必要がありますString

  • 大文字で始まる単語のパーサー。

  • 他のすべてのパーサー。コンパスの方向ではないトークンや大文字で始まる単語を検出すると成功します。

  • 任意のトークンで機能するパーサーですが、おそらく代数的データ型を使用して、良いものと悪いものを区別します。

  • たくさんのトークンで動作するパーサー

うまくいけば、それはあまり明確にならずに明確です。たとえば、ジャンクをいつ破棄するかについては、まだ心配する必要があります。基本的な考え方は、問題を多くの小さなサブ問題に分解し、サブ問題を解決してから、それらの解決策を接着することです。

于 2012-10-26T16:11:47.733 に答える
4

私がどのように始めるかをあなたに話し、それから私がどのように続けるかについてアドバイスするつもりです。

これは抽象的なデータ構造に基づいています。単語を追加すると、それらをより厳密に分類できます。

data Word = Country String | Direction NSEW | Unclassified String
data NESW = North | East | South | West

ですから、あなたが知らない単語をスキップする方法に対する私の答えは、あなたがする必要がないということです-それらを未分類のままにしておきます。

適用スタイルは、モナディックスタイルよりも優れています。

私はcompassDirection大文字を許可する必要があると思います:

compassDirection :: Parser NESW
compassDirection = north <|> south <|> east <|> west where
    north = North <$ (string "north" <|> string "North")
    east = ...

countryを使用して定義できますCountry <$> ((:) <$> upper <*> many lower)

次に、キャッチオールを持つことができますUnclassified <$> many letter

あなたのワードパーサーは現在

word = compassDirection <|> country <|> unclassified

しかし、そうでなければ一致するので、それはcompassDirection前に来なければならないことに注意してください。countrycountryNorth

できるよ

words = word `sepBy1` space

現時点では問題ありませんが、単語が何であるかを制御できなくなるため、文章をより適切に分析する場合は使用しwordないでください。wordsその時点で、文型をパスするために、、、、、などが必要nounになります。解析できない文は、文法に新しい構成を追加する必要があることを意味します。adjectivenounPhraseverbadjectiveadjectivalPhrase

単語パーサーに空白の後(または前)を飲み込ませるか、単語をスペースと句読点から分割するプリプロセッサーを使用してリファクタリングすることは価値があります。fullStopイギリス人の場合はperiodパーサー、アメリカ人の場合はパーサーを検討してください。文パーサーを作成するときに使用します。

適用可能で高階関数を使用すると、文法が単調な表記で乱雑にならず、文のように見えるため、文法の記述がはるかに明確になります。例:nvn = NVN <$> noun <*> verb <*> noun文法オブジェクトごとに1つのコンストラクターを使用して、主に抽象データ構造(AST)アプローチを使用する場合に実行できます。同じタイプのすべての単語の周りにたくさんの単語を置きたいだけの場合は、を行うことができますnvn = sequence [noun,verb,noun]

ほとんどのコンピューター言語はASTアプローチを使用して解析されますが、妻の言語学の学位から直接習得したものを超えて、自然言語の解析を直接経験したことはありません。

座って、単語、フレーズ、句、文のカテゴリを組み合わせる方法を書くと、パーサーをかなりすばやく書くことができます。

于 2012-10-26T18:20:29.733 に答える
0

文字列を大文字で始まる文字列またはコンパス方向の文字列に分割してから、元に戻すことはできませんwordsか?銃を抜く必要はありません。filterunwordsParsec

于 2012-10-26T17:24:43.680 に答える