17

HaskellのParsecのインデントパッケージは、インデントスタイルの言語(HaskellやPythonなど)を解析する方法を提供します。タイプを再定義しますが、Parsecのモジュールによってエクスポートされた通常のタイプParserのトークンパーサー関数をどのように使用しますか?Text.Parsec.TokenParser

バックグラウンド

Parsecには多数のモジュールが付属しています。それらのほとんどは、有用なパーサー(たとえば、改行を解析する newlinefrom )またはパーサーコンビネーター(たとえば、パーサーpn回実行するfrom )をエクスポートします。Text.Parsec.Charcount n pText.Parsec.Combinator

ただし、モジュールText.Parsec.Tokenは、解析対象の言語の機能を使用してユーザーがパラメーター化した関数をエクスポートする必要があるため、たとえば、関数は「{」を解析した後、「}」を解析する前にbraces pパーサーpを実行します。コメントのようなものを無視します。コメントの構文は言語によって異なります。

これを実現する方法は、呼び出すText.Parsec.Token単一の関数makeTokenParserをエクスポートして、特定の言語のパラメーター(コメントの外観など)を指定し、のすべての関数を含むレコードを返し、そのText.Parsec.Token言語に適合させることです。指定。

もちろん、インデントスタイルの言語では、これらをさらに適応させる必要があります(おそらく、ここでわかりません。後で説明します)。したがって、(おそらく廃止された)IndentParserパッケージがモジュールを提供することに注意してください。Text.ParserCombinators.Parsec.IndentParser.Tokenこれは、のドロップイン置換のように見えますText.Parsec.Token

ある時点で、すべてのParsecパーサーはモナディック関数であるため、エラーメッセージがソースファイルのどの行と列でエラーが発生したかを示すことができるように、状態を魔法のように処理します。

私の問題

いくつかの小さな理由から、インデントパッケージは多かれ少なかれ現在のバージョンのIndentParserであるようText.ParserCombinators.Parsec.IndentParser.Tokenに見えますが、のようなモジュールは提供されておらず、提供されているだけなText.Parsec.Indentので、どうすれば取得できるのでしょうか。からのすべてのトークンパーサーText.Parsec.Tokenreserved "something"予約されたキーワード「something」を解析するもの、またはbraces前述したものなど)。

(新しい)Text.Parsec.Indentは、ある種のモナディック状態の魔法によってソースコードの列ビットが何であるかを理解するように見えるので、whiteSpacefromのようにトークンパーサーを変更する必要はありませんText.Parsec.Token。これがおそらくそれが理由です。交換用モジュールは提供していません。しかし、私は型に問題があります。

がないText.Parsec.Indent場合、すべてのパーサーはタイプParser Somethingであり、Somethingは戻りタイプでありParser、Text.Parsec.Stringで次のように定義されたタイプエイリアスです。

type Parser = Parsec String ()

しかし、Text.Parsec.Indentをインポートする代わりにText.Parsec.String、私は自分の定義を使用します

type Parser a = IndentParser String () a

これにより、すべてのパーセクがタイプになります。ここで、IndentParserはText.Parsec.Indentで定義されています。しかし、私が取得しているトークンパーサーは間違ったタイプです。IndentParser String () SomethingmakeTokenParserText.Parsec.Token

これが今ではあまり意味をなさないのなら、それは私が少し迷っているからです。タイプの問題については、ここで少し説明します


私が得ているエラーは、Parser上記の1つの定義を別の定義に置き換えようとしたが、からのトークンパーサーの1つを使用しようとするとText.Parsec.Token、コンパイルエラーが発生することです。

Couldn't match expected type `Control.Monad.Trans.State.Lazy.State
                                Text.Parsec.Pos.SourcePos'
            with actual type `Data.Functor.Identity.Identity'
Expected type: P.GenTokenParser
                 String
                 ()
                 (Control.Monad.Trans.State.Lazy.State Text.Parsec.Pos.SourcePos)
  Actual type: P.TokenParser ()

リンク

残念ながら、上記の例はどちらも、Text.Parsec.Tokenのようなトークンパーサーを使用していません。

4

1 に答える 1

14

あなたは何をしようとしているのですか?

パーサーをあらゆる場所でタイプとして定義してもらいたいようです。

Parser Something

Somethingがリターンタイプである場合)そして、Parser通常インポートされるタイプText.Parsec.Stringまたは類似のものを非表示にして再定義することにより、これを機能させるため。Text.Parsec.StringStreamをモナドのインスタンスにするには、まだいくつかをインポートする必要があります。次の行でこれを行います:

import Text.Parsec.String ()

あなたの定義Parserは正しいです。代わりに、同等に(コメントでチャットをフォローしている人のために)あなたは使うことができます

import Control.Monad.State
import Text.Parsec.Pos (SourcePos)

type Parser = ParsecT String () (State SourcePos)

そして、おそらくimport Text.Parsec.Indent (IndentParser)この定義が表示されているファイル内のを削除します。

エラー、壁のエラー

問題は、コンパイラのエラーメッセージの間違った部分を見ていることです。あなたは焦点を合わせています

Couldn't match expected type `State SourcePos' with actual type `Identity'

あなたが焦点を当てるべきとき

Expected type: P.GenTokenParser ...
  Actual type: P.TokenParser ...

コンパイルします!

パーサーをから「インポート」するText.Parsec.Token場合、もちろん(簡単に述べたように)実際に行うことは、最初に言語パラメーターのレコードを定義し、次にこれを関数に渡すことです。この関数makeTokenParserは、トークンパーサーを含むレコードを返します。

したがって、次のような行が必要です。

import qualified Text.Parsec.Token as P

beetleDef :: P.LanguageDef st
beetleDef =
    haskellStyle {
        parameters, parameters etc.
        }

lexer :: P.TokenParser ()
lexer = P.makeTokenParser beetleDef

...しかし、aP.LanguageDef stは単なる、GenLanguageDef String st Identityであり、aP.TokenParser ()は実際にはGenTokenParser String () Identityです。

タイプ宣言を次のように変更する必要があります。

import Control.Monad.State
import Text.Parsec.Pos (SourcePos)
import qualified Text.Parsec.Token as P

beetleDef :: P.GenLanguageDef String st (State SourcePos)
beetleDef =
    haskellStyle {
        parameters, parameters etc.
        }

lexer :: P.GenTokenParser String () (State SourcePos)
lexer = P.makeTokenParser beetleDef

... 以上です!これにより、「インポートされた」トークンパーサーが(のエイリアスである)の代わりにタイプを持つことができるようになり、コードがコンパイルされるようになります。ParsecT String () (State SourcePos) SomethingParsec String () SomethingParsecT String () Identity Something

Parser(最大限の一般性のために、実際のパーサー関数を定義するファイルとは別のファイルでタイプを定義し、それによってインポートされる可能性があると想定しています。したがって、2つの繰り返されるimportステートメント。)

ありがとう

これを手伝ってくれたDanielFischerに感謝します。

于 2013-03-11T16:19:06.297 に答える