views:

73

answers:

1
parserChar :: Char -> Parser Char
parserChar c = Parser ch where
   ch d = case dvChar d of
      Parsed c dp -> Parsed c dp
      _ -> NoParse

The above function is supposed to take a Char c and return a Parser which will only match c. The function dvChar d is going to return either Parsed char dp or NoParse (where char is the next character in the string). Thus, I had hoped that Parsed c dp would only match a result in which char==c, but what's actually happening is that the Parser returned by this function matches any character (even though c seems to be bound to some particular Char, as a function argument).

The following function works correctly:

parserChar :: Char -> Parser Char
parserChar c = Parser ch where
   ch d = case dvChar d of
      Parsed char dp -> if char == c then Parsed char dp else NoParse
      _ -> NoParse

Manually coding the parser to parse the letter 'a' also works correctly, in that

case dvChar d of
   Parsed 'a' dp -> Parsed 'a' dp
   _ -> NoParse

will only return success if the character was 'a'.

So what gives? Can you only match literals in a pattern like that (e.g. despite the fact that Char is in class Eq, the if char==c (..) still needs to be coded manually), or am I doing something wrong?

+6  A: 

Yes, you can only match literals. In fact, a better way to think about it is that you can only match constructors, and it so happens that Int, Char, String & co. all have literal constructors.

Note that you can also mix case and guards and write it as (from memory):

parserChar :: Char -> Parser Char
parserChar c = Parser ch where
   ch d = case dvChar d of
      Parsed char dp | char == c -> Parsed char dp
      _ -> NoParse
sclv