约束(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
答案 0 :(得分:12)
约束:( Stream s Identity t)意味着什么?
这意味着您的解析器工作的输入s
(即[Char]
)必须是Stream
类的实例。在documentation中,您看到[Char]
确实是Stream的一个实例,因为任何列表都是。
参数t
是令牌类型,通常为Char
,并由s
确定,表示功能依赖s -> t
。
但是不要过多担心这个Stream类型类。它仅用于具有任何类似Stream的类型的统一接口,例如列表或字节串。
什么是Stream
Stream只是一个类型类。它具有uncons
函数,它返回输入的头部和尾部,包含在Maybe
中的元组中。通常你不需要这个功能。据我所知,它只需要最基本的解析器,如tokenPrimEx
。
修改
这个'上下文'的含义是什么,因为在=&gt;
之后t从未显示过
看看functional dependencies。 t
永远不会在'=&gt;'之后显示,因为它由s
决定。
这意味着您可以uncons
使用s
。
这是我的代码,无法加载,我该如何使其工作?
简单:为Text.Parsec.String
添加导入语句,该语句定义Stream [tok] m tok
的缺失实例。这里的文档可能更清晰一些,因为它看起来好像是Text.Parsec.Prim
中定义了这个实例。
或者导入整个Parsec库(import Text.Parsec
) - 这就是我一直这样做的。
答案 1 :(得分:11)
Stream
类型类是类似列表的数据结构的抽象。早期版本的Parsec仅用于解析令牌列表(例如,String
是[Char]
的同义词,因此Char
是令牌类型),这可能是一种效率非常低的表示。这些天,Haskell中的大多数实质性输入都被处理为Text
或ByteString
类型,这些类型不是列表,但可以像它们一样行事。
所以,例如,你提到
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也适用于你的类型。