What does the constraint (Stream s Identity t)
mean in the following type declaration?
parse :: (Stream s Identity t)
=> Parsec s () a -> SourceName -> s -> Either ParseError a
What is Stream
in the following class declaration, what does it mean. I'm totally lost.
class Monad m => Stream s m t | s -> t where
When I use Parsec, I get into a jam with the type-signatures (xxx :: yyy
) all the time. I always skip the signatures, load the src into ghci, and then copy the type-signature back to my .hs file. It works, but I still don't understand what all these signatures are.
EDIT: more about the point of my question.
I'm still confused about the 'context' of type-signature:
(Show a) =>
means a
must be a instance of class Show
.
(Stream s Identity t) =>
what's the meaning of this 'context', since t
never showed after the =>
I have a lot of different parser to run, so I write a warp function to run any of those parser with real files. but here comes the problem:
Here is my code, It cannot be loaded, how can I make it work?
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
the constraint: (Stream s Identity t) means what?
It means that the input s
your parser works on (i.e. [Char]
) must be an instance of the Stream
class. In the documentation you see that [Char]
is indeed an instance of Stream, since any list is.
The parameter t
is the token type, which is normally Char
and is determinded by s
, as states the functional dependency s -> t
.
But don't worry too much about this Stream typeclass. It's used only to have a unified interface for any Stream-like type, e.g. lists or ByteStrings.
what is Stream
A Stream is simply a typeclass. It has the uncons
function, which returns the head of the input and the tail in a tuple wrapped in Maybe
. Normally you won't need this function. As far as I can see, it's only needed in the most basic parsers like tokenPrimEx
.
Edit:
what's the meaning of this 'context', since t never showed after the =>
Have a look at functional dependencies. The t
never shows after the ´=>´, because it is determiend by s
.
And it means that you can use uncons
on whatever s
is.
Here is my code, It cannot be loaded, how can I make it work?
Simple: Add an import statement for Text.Parsec.String
, which defines the missing instance for Stream [tok] m tok
. The documentation could be a bit clearer here, because it looks as if this instance was defined in Text.Parsec.Prim
.
Alternatively import the whole Parsec library (import Text.Parsec
) - this is how I always do it.
The Stream
type class is an abstraction for list-like data structures. Early versions of Parsec only worked for parsing lists of tokens (for example, String
is a synonym for [Char]
, so Char
is the token type), which can be a very inefficient representation. These days, most substantial input in Haskell is handled as Text
or ByteString
types, which are not lists, but can act a lot like them.
So, for example, you mention
parse :: (Stream s Identity t)
=> Parsec s () a -> SourceName -> s -> Either ParseError a
Some specializations of this type would be
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
or even, if you have a separate lexer with a token type MyToken
:
parse4 :: Parsec [MyToken] () a -> SourceName -> [MyToken] -> Either ParseError a
Of these, only the first and last use actual lists for the input, but the middle two use other Stream
instances that act enough like lists for Parsec to work with them.
You can even declare your own Stream
instance, so if your input is in some other type that acts sort of list-like, you can write an instance, implement the uncons
function, and Parsec will work with your type, as well.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With