Search code examples
haskelltypestypeclassinduction

Implementing instance of Read typeclass in haskell


I've been playing around with inductive types (defined natural numbers and arithmetic operations on them) a little bit, and I can't get Haskell read function to work.

Here's my code:

data Natural = Zero | Succ Natural
    deriving (Eq, Ord)

instance Enum Natural where
    pred Zero = undefined
    pred (Succ x) = x

    succ x = Succ x

    toEnum 0 = Zero
    toEnum x = Succ (toEnum (x - 1))

    fromEnum Zero = 0
    fromEnum (Succ x) = fromEnum x + 1

instance Num Natural where
    (+) x Zero = x
    (+) x (Succ y) = Succ (x + y)

    (-) Zero (Succ x) = undefined
    (-) x Zero = x
    (-) (Succ x) (Succ y) = x - y

    (*) x Zero = Zero
    (*) x (Succ y) = x * y + x

    abs x = x

    signum Zero = Zero
    signum (Succ x) = Succ Zero

    fromInteger 0 = Zero
    fromInteger x = Succ (fromInteger (x - 1))

instance Show Natural where
    show x = show $ fromEnum x

-- Not working!

instance Read Natural where
    readsPrec x = fromInteger $ (read x) :: Integer

I want this expression to be valid: naturalNumber = read someStringWithInteger :: Natural, so I can't just derive Read typeclass.

I've tried using readsPrec and readPrec, but I only get mismatched type errors.

How do I implement an instance of Read typeclass?


Solution

  • Your function has the wrong type. Your readsPrec has type String -> Natural, whereas you should have used Int -> String -> [(Natural, String)]. But we can adjust that:

    readsPrec p s = [(fromInteger i, s') | (i, s') <- readsPrec p s]
    

    This uses Integer's readsPrec function. Since you want to read Integers it's just fitting to use it for convenience.

    For symmetry reasons, I suggest you to implementshowsPrec instead of show in your Show instance.