Stream s m t クラス
Stream s m t クラス
Stream s m t クラスはただ一つの多相関数 uncons を持つクラスだ。
class (Monad m) => Stream s m t | s -> t where uncons :: s -> m (Maybe (t,s))
コメントによると s は stream type, m は underlying monad, t は token type の意味だ。
s が String 型の場合、uncons s の値は、m (head s, tail s) と同じものになる。
Prelude> :m Text.Parsec Prelude Text.Parsec> uncons "hello" Just ('h',"ello")
uncons の値のタイプを :t コマンドでみると、Just ('h', "ello") ではなくモナド m にラッピングされていることが分かる。
Prelude Text.Parsec> :t uncons "hello" uncons "hello" :: Monad m => m (Maybe (Char, [Char]))
uncons 多相関数
s には文字列以外に uncons 関数をもつ Data.ByteString などのリストではない文字列も使うことができる。Text.Parsec.Prim では次のようなモジュールがインストールされている。
import qualified Data.ByteString.Lazy.Char8 as CL import qualified Data.ByteString.Char8 as C
import Data.Typeable ( Typeable )
import qualified Data.Text as Text import qualified Data.Text.Lazy as TextL
これらのデータ構造は次のように Stream クラスのインスタンスに宣言されている。
class (Monad m) => Stream s m t | s -> t where uncons :: s -> m (Maybe (t,s))
instance (Monad m) => Stream [tok] m tok where uncons [] = return $ Nothing uncons (t:ts) = return $ Just (t,ts) {-# INLINE uncons #-}
instance (Monad m) => Stream CL.ByteString m Char where uncons = return . CL.uncons
instance (Monad m) => Stream C.ByteString m Char where uncons = return . C.uncons
instance (Monad m) => Stream Text.Text m Char where uncons = return . Text.uncons {-# INLINE uncons #-}
instance (Monad m) => Stream TextL.Text m Char where uncons = return . TextL.uncons {-# INLINE uncons #-}
これらのことは、uncons 関数が String 型だけでなく、ByteString 型や、Text 型、トークンのリストにまで適用できることが分かる。これは、パーサが入力文字列として String 型以外のデータにもそれほどの変更もなく使えることを意味している。
しかし、パーサモナドのコードの解析のためには Stream s m t の s は文字列だと思っても問題ないので、コードのなかに uncons 関数が出てきたら String 型に使われているのだと考えることにする。