Home > front end >  string to Integer parsing with Exception Handling in Haskell
string to Integer parsing with Exception Handling in Haskell

Time:06-03

Trying to make type nat which return [ (int, string) ]; handle zero as string

and type int which can handle negative integer also.

import Data.Char ( isDigit )    

type Parser tok a = [tok] -> [(a, [tok])] 
    
return :: a -> Parser tok a 
return v = \ts -> [(v, ts)]

failure :: Parser tok a 
failure = \_ -> [] 

item :: Parser tok tok 
item []     = []
item (t:ts) = [(t, ts)] 

sat :: (tok -> Bool) -> Parser tok tok 
sat test = item >>= \t -> 
           if test t then return t 
                     else failure 

(<|>) :: Parser tok a -> Parser tok a -> Parser tok a 
p1 <|> p2 = \ts -> case p1 ts of 
                     [] -> p2 ts
                    rs1 -> rs1

many1 :: Parser tok a -> Parser tok [a] 
many  p = many1 p <|> return []
many1 p = p      >>= \v  -> 
          many p >>= \vs -> 
          return (v:vs)

digit = sat isDigit 

first I make nat and use if ~ then ~ else make exception of 0.

nat :: Parser Char Int 
nat = many1 digit >>= \s -> 
      if (s == "0") then failure 
                    else return (read s) 

It was able to handle one zero.

nat "0"
> [] 

nat "0def" 
> [] 

but can't handle when consecutive numbers starting with 0 come to input.

nat "012def" 
> [(12, "def")] -- probably my code only handle 1 Zero
-- expect return [] 

nat "000def" 
> [(0, "def")]  -- but i really don't know why this output is coming 
-- expect return [] 

I tried to put aside the problem about nat and make an int first.

first I tried to use nat to define int.

int :: Parser Char Int 
int = nat >>= \s -> 
      if (s < 0) then return (-s) 
                 else return s 

And I realize that i can't make to compiler recognize that s is negative.

so i tried to make it simillar as nat. which I want to add char '-'?

int :: Parser Char Int 
int = many1 digit >>= \s -> 
      if (s == "-") then return (read s)    "-"  
                    else return (read s) 

I have two question

  1. Why nat only handle 1 zero? I thought many1 is recursive parsing string step-by-step.

  2. How can I add "-" in int? does it related with thins like synthetic function?

I am weak at using Haskell. is there something i'm missing?

CodePudding user response:

Don't panic. It is not so difficult.

  1. Why nat only handle 1 zero? I thought many1 is recursive parsing string step-by-step.

You are right many1 digit will apply the parser digit on the longer chain possible. This means that when you are parsing 012def the parsed part is "012" and the remaining is "def". But you are missing where the error is. It is in the following

\s -> if (s == "0") then failure 
                    else return (read s)

Once, many1 digit finish it provides "012" to your function via the bind (>>=) and it is process. But "012" is not "0". So the else part is applied : return (read "012"). The context "def" is not modified. So this results to the answer [12,"def"]. As you can see the problem is not the first part of the bind, but the second one. Since you know that you will only get digit (because many1 digit can only parse digit), I suggest that you change your binder with

let n = read s 
in if n == 0 then failure 
             else n

More elegant (monadic) solution are possibles, but this one is probably quite readable and explicit for new haskeller.

  1. How can I add "-" in int? does it related with thins like synthetic function?

You can't. You want to read a Char that cannot be translate as a digit. So you can't read it as digit. This is a simple parsing problem. You have to deal with the '-' separately. You can use a choice between two parsers. The first parses the Char '-' followed by a natural. The second parses only natural. Then translate the result in an Int. Take care to not forget the 0. It can be handle in the first, the second or both. This means that you can't use nat in both... or you will have to make a third parser that only parse 0. So remember that the order is important.

I am pretty sure that can be write this considering the previous work. You already have the digit and the choice combinator. The char parser is pretty obvious. You just have to think about it.

Hope this will help.

  • Related