2

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?

1
  • 1
    "I've tried using readsPrec and readPrec, but I only get mismatched type errors." - this is the correct way to go. You should include your type errors. readPrec = fmap fromInteger . readPrec should work. (Aside: show $ fromEnum x will give an error for naturals which don't fit into Int. You should implement Integral Natural and then write show $ toInteger x) Commented Aug 19, 2017 at 15:19

1 Answer 1

5

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.

Sign up to request clarification or add additional context in comments.

4 Comments

I'm new to Haskell and what you wrote seems hard to me. Could you suggest me some ways to implement showsPrec instead of show?
Same way I've implemented readsPrec, namely in terms of showsPrec p n where n is an Int. You already have a way to build an Int out of a Natural. Unfortunately, both readsPrec and showsPrec use slightly "obfuscated" types due to ReadS and ShowS, but it gets slightly easier if you wrote them out.
According to :i showsPrec and :i ShowS, I got the full signature for showsPrec: showsPrec :: Int -> a -> String -> String. But you've written showsPrec p n (only 2 arguments). Where am I wrong?
I'm not sure whether you know this already, but instead of writing addFive x = (+) 5 x, one can also write addFive = (+) 5. This is called partial application. But you can be explicit and write showsPrec p n s = showsPrec p (magic n) s (where you have to replace magic with another function).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.