Parsec函数'parse'的类型签名和类'Stream'

Nyb*_*ble 10 haskell types parsec

约束(Stream s Identity t)在以下类型声明中意味着什么?

parse :: (Stream s Identity t)
  => Parsec s () a -> SourceName -> s -> Either ParseError a
Run Code Online (Sandbox Code Playgroud)

什么是Stream在下面的类的声明,这是什么意思.我完全迷失了.

class Monad m => Stream s m t | s -> t where
Run Code Online (Sandbox Code Playgroud)

当我使用Parsec时,我总是遇到带有type-signature(xxx :: yyy)的卡纸.我总是跳过签名,将src加载到ghci,然后将类型签名复制回我的.hs文件.它有效,但我仍然不明白所有这些签名是什么.


编辑:更多关于我的问题.

我仍然对类型签名的"上下文"感到困惑:

(Show a) =>
Run Code Online (Sandbox Code Playgroud)

意味着a必须是一个类的实例Show.

(Stream s Identity t) => 
Run Code Online (Sandbox Code Playgroud)

这种"背景"的含义是什么,因为t从未在此之后展示过=>


我有很多不同的解析器要运行,所以我编写了一个warp函数来运行任何带有真实文件的解析器.但问题出现了:

这是我的代码,它无法加载,我怎样才能使它工作?

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
Run Code Online (Sandbox Code Playgroud)

bzn*_*bzn 12

约束:( Stream s Identity t)意味着什么?

这意味着s解析器的输入(即[Char])必须是Stream类的实例.在文档中,您看到[Char]的确实是Stream的一个实例,因为任何列表都是.

该参数t是所述令牌类型,这是通常Chardeterminded通过s作为规定的功能依赖性s -> t.

但是不要过多担心这个Stream类型类.它仅用于为任何类似流的类型提供统一接口,例如列表或字节串.

什么是流

Stream只是一个类型类.它具有uncons函数,它返回输入的头部和包裹在元组中的尾部Maybe.通常你不需要这个功能.据我所知,它只需要在最基本的解析器中使用tokenPrimEx.

编辑:

这个'上下文'是什么意思,因为在=>之后t从未显示过

看看功能依赖.在t从未示出后的'=>',因为它是由determiend s.这意味着你可以使用uncons任何东西s.

这是我的代码,它无法加载,我怎样才能使它工作?

简单:为其添加import语句Text.Parsec.String,该语句定义了缺少的实例Stream [tok] m tok.这里的文档可能会更加清晰,因为它看起来好像是在定义了这个实例Text.Parsec.Prim.

或者导入整个Parsec库(import Text.Parsec) - 这就是我经常这样做的方式.


Chr*_*ith 11

Stream类型的类是用于列表类似的数据结构的抽象.Parsec的早期版本仅用于解析令牌列表(例如,String是令牌的同义词[Char],因此Char是令牌类型),这可能是非常低效的表示.这些天,Haskell中的大多数实质性输入都是作为TextByteString类型处理的,它们不是列表,但可以像它们一样行动.

所以,例如,你提到

parse :: (Stream s Identity t)
  => Parsec s () a -> SourceName -> s -> Either ParseError a
Run Code Online (Sandbox Code Playgroud)

这种类型的一些专业将是

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
Run Code Online (Sandbox Code Playgroud)

或者甚至,如果你有一个带有令牌类型的独立词法分析器MyToken:

parse4 :: Parsec [MyToken] () a -> SourceName -> [MyToken] -> Either ParseError a
Run Code Online (Sandbox Code Playgroud)

其中,只有第一个和最后一个使用输入的实际列表,但是中间两个使用其他Stream像Parsec列表一样的实例来处理它们.

您甚至可以声明自己的Stream实例,因此如果您的输入是某种类似列表的其他类型,您可以编写实例,实现该uncons函数,Parsec也可以使用您的类型.