Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Haskell instance read for newtype that is just an int

I am new to Haskell and I want to be able to a newtype so I can tell what is what, but I also have to read it from a string. I have

newtype SpecialId Int
    deriving (Eq, Ord, Show)

I want to be able to read "5" :: SpecialId if I derive Read in the newtype it doesn't work it only works on read "SpecialId 5" :: SpecialId. I have tried

instance Read SpecialId where
    readsPrec _ s = read s

But this gives me

SpecialId *** Exception: Prelude.read: no parse
like image 211
Ross MacArthur Avatar asked Dec 08 '22 16:12

Ross MacArthur


2 Answers

This is possible since GHC 8.2 using -XDerivingStrategies:

{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE DerivingStrategies         #-}

newtype SpecialId = SpecialId Int
    deriving stock   (Eq, Ord, Show)
    deriving newtype Read

In ghci:

ghci> read "5" :: SpecialId 
SpecialId 5
like image 95
Shersh Avatar answered Jan 15 '23 13:01

Shersh


You don't need a language extension if you're willing to forward to the Int instance manually:

instance Read SpecialId where
    readsPrec n s = [ (SpecialId x, y) | (x, y) <- readsPrec n s ]

Despite appearances this is not a recursive use of readsPrec: We call the Int version of readsPrec to get a list of (Int, String) pairs, then we use a list comprehension to wrap every Int in a SpecialId.

like image 40
melpomene Avatar answered Jan 15 '23 14:01

melpomene