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) =>

手段a必须是类的一个实例Show

(Stream s Identity t) => 

这个“上下文”是什么意思,因为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
4

2 回答 2

12

约束:(Stream s Identity t)是什么意思?

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

参数t是令牌类型,通常Char确定s如功能依赖项所述s -> t

但是不要太担心这个 Stream 类型类。它仅用于为任何类似 Stream 的类型(例如列表或 ByteStrings)提供统一的接口。

什么是流

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

编辑:

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

看看功能依赖t'=>' 之后从不显示,因为它是由 确定的s。这意味着你可以使用uncons任何东西s

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

很简单:添加一个导入语句 for 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

其中,只有第一个和最后一个使用实际列表作为输入,但中间两个使用其他Stream实例,这些实例的作用与 Parsec 的列表非常相似,可以使用它们。

你甚至可以声明你自己的Stream实例,所以如果你的输入是其他类似列表的类型,你可以编写一个实例,实现这个uncons函数,Parsec 也可以使用你的类型。

于 2011-06-16T16:31:02.803 回答