10

(Stream s Identity t)次の型宣言の制約はどういう意味ですか?

parse :: (Stream s Identity t)
  => Parsec s () a -> SourceName -> s -> Either ParseError a

Stream次のクラス宣言には何がありますか、それはどういう意味ですか。私は完全に迷っています。

class Monad m => Stream s m t | s -> t where

Parsec を使用していると、型シグネチャ ( xxx :: yyy) でいつも渋滞に陥ります。私は常に署名をスキップし、src を ghci にロードしてから、型署名を .hs ファイルにコピーします。動作しますが、これらすべての署名が何であるかはまだわかりません。


編集:私の質問のポイントについての詳細。

タイプシグネチャの「コンテキスト」についてまだ混乱しています:

(Show a) =>

meansaは class のインスタンスでなければなりませんShow

(Stream s Identity t) => 

この「コンテキスト」の意味は何ですかt?=>


実行するパーサーがたくさんあるので、ワープ関数を作成して、実際のファイルでそれらのパーサーを実行します。しかし、ここに問題があります:

これが私のコードです。ロードできません。どうすれば動作させることができますか?

module RunParse where
import System.IO
import Data.Functor.Identity (Identity)
import Text.Parsec.Prim (Parsec, parse, Stream)

--what should I write "runIOParse :: ..."
--runIOParse :: (Stream s Identity t, Show a) => Parsec s () a -> String -> IO ()
runIOParse pa filename =
  do
    inh <- openFile filename ReadMode
    outh <- openFile (filename ++ ".parseout") WriteMode
    instr <- hGetContents inh
    let result = show $ parse pa filename instr
    hPutStr outh result
    hClose inh
    hClose outh
4

2 に答える 2

12

制約: (Stream s Identity t) の意味は?

sこれは、パーサーが処理する入力(つまり ) がクラス[Char]のインスタンスでなければならないことを意味します。ドキュメントStreamでは、すべてのリストがそうであるため、実際に Stream のインスタンスであることがわかります。[Char]

パラメータtはトークン タイプであり、通常Charによって決定されsますs -> t

しかし、この Stream 型クラスについてはあまり心配する必要はありません。これは、リストや ByteString など、ストリームに似た型の統一されたインターフェイスを持つためにのみ使用されます。

ストリームとは

Stream は単なる型クラスです。でuncons囲まれたタプルで入力の先頭と末尾を返す関数がありますMaybe。通常、この関数は必要ありません。私が見る限り、これは のような最も基本的なパーサーでのみ必要ですtokenPrimEx

編集:

=> の後に t が表示されなかったため、この「コンテキスト」の意味は何ですか

機能依存関係を見てください。によって決定されるため、'=>'のt後に が表示されることはありませんsunconsそして、それはあなたが何にでも使えることを意味しますs

これが私のコードです。ロードできません。どうすれば動作させることができますか?

簡単: のインポート ステートメントを追加します。Text.Parsec.Stringこれは、 の不足しているインスタンスを定義しますStream [tok] m tok。このインスタンスはText.Parsec.Prim.

または、Parsec ライブラリ全体をインポートします ( import Text.Parsec)。これは、私がいつも行っている方法です。

于 2011-06-16T12:25:45.390 に答える
11

Stream型クラスは、リストのようなデータ構造の抽象化です。Parsec の初期のバージョンは、トークンのリストを解析する場合にのみ機能し (たとえば、Stringは のシノニムであり、トークン タイプ[Char]もそうCharです)、これは非常に非効率的な表現になる可能性があります。最近では、Haskell の最も実質的な入力はTextorByteString型として処理されます。これはリストではありませんが、それらのように振る舞うことができます。

したがって、たとえば、あなたは言及します

parse :: (Stream s Identity t)
  => Parsec s () a -> SourceName -> s -> Either ParseError a

このタイプのいくつかの専門分野は次のとおりです。

parse1 :: Parsec String () a -> SourceName -> String -> Either ParseError a
parse2 :: Parsec Text () a -> SourceName -> Text -> Either ParseError a
parse3 :: Parsec ByteString () a -> SourceName -> ByteString -> Either ParseError a

または、トークン タイプの別のレクサーがある場合でも、次のようになりますMyToken

parse4 :: Parsec [MyToken] () a -> SourceName -> [MyToken] -> Either ParseError a

これらのうち、最初と最後のものだけが入力に実際のリストを使用しますが、中間の 2 つStreamは、Parsec がそれらを操作するのにリストのように十分に機能する他のインスタンスを使用します。

独自のインスタンスを宣言することもできるStreamので、入力がリストのような動作をする他の型の場合、インスタンスを作成してuncons関数を実装すると、Parsec はその型でも動作します。

于 2011-06-16T16:31:02.803 に答える