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
    "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`) – user2407038 Aug 19 '17 at 15:19

1 Answers1

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.

Zeta
  • 103,620
  • 13
  • 194
  • 236
  • 1
    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`? – Alex Danilov Aug 19 '17 at 15:31
  • 1
    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. – Zeta Aug 19 '17 at 15:36
  • 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? – Alex Danilov Aug 19 '17 at 15:59
  • 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). – Zeta Aug 19 '17 at 16:48