Quantcast
Channel: Haskell Parser not working - Stack Overflow
Viewing all articles
Browse latest Browse all 2

Answer by kosmikus for Haskell Parser not working

$
0
0

Please use code that compiles. Your another function does not.

What's the problem?

Your code for firstlast and another makes use of do-notation. And the way you're using pitem here, it looks as if you're expecting Parser to be a monad. But it isn't, at least not in the way you expect it to be.

There is a monad instance pre-defined which make GHC think that Parser is a monad, namely

instance Monad ((->) r) where  return = const  f >>= k = \ r -> k (f r) r

What this instance says is that, for any type r the function type r -> ... can be considered a monad, namely by distributing the parameter everywhere. So returning something in this monad amounts to producing a value ignoring the parameter of type r, and binding a value means that you take r and pass it on both to the left and right computation.

This is not what you want for a parser. The input string will be distributed to all computations. So each pitem will operate on the original input string. Furthermore, as

pitem :: String -> [(Char, String)]

the result of your monadic computation will be of type [(Char, String)], so x and y are both of this type. That's why you get the result

[(([('a',"bc")],[('a',"bc")]),"abc")]

You're calling pitem three times on the same input string. You're putting two results in a pair, and you're preturn-ing the whole thing.

How to fix it?

You need to define your own monad instance for the Parser type. You cannot do that directly, because Parser is a type synonym, and type synonyms cannot be partially applied,so you cannot write

instance Monad Parser where  ...

Instead, you have to wrap Parser in a new datatype or newtype:

newtype Parser a = Parser { parse :: String -> [(a, String)] }

This gives you a constructor Parser and a function parse to convert between the unwrapped and wrapped parser types:

Parser :: String -> [(a, String)] -> Parser aparse  :: Parser a -> String -> [(a, String)]

This implies you'll have to adapt your other functions. For example, preturn becomes

preturn :: a -> Parser a preturn t = Parser (\inp -> [(t,inp)])

Change pfailure and pitem similarly. Then, you have to define the Monad instance:

instance Monad Parser where  return = preturn  (>>=)  = ... -- to be completed by you

The function (>>=) is not contained in your code above. You'll want to implement the behaviour that the input is passed to the first parser, and for every result of that, the result and the remaining input are passed to the second argument of (>>=). Once this is done, a call to parse firstlast "abc" will have the following result:

[(('a','c'),"")]

which isn't quite what you want in your question, but I believe it's what you're actually after.


Viewing all articles
Browse latest Browse all 2

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>