Search code examples
haskelltypeclass

Overloading Show and Num in typeclass makes execution hang indefinitely


I am making assigment on Haskell, and almost solved it.. Feels like I miss some last step, but cant put my finger on, what do I do wrong.

First my task:

Now, insted of using type synonyms, define data types CountryCode and PhoneNo so that both of them have a value constructor that takes an integer. Derive an instance for Eq, Ord and Show for PhoneType. Derive instances for Eq and Ord for CountryCode and PhoneNo and make Show instances for them so that: CountryCode: print '+' in front of the number. PhoneNo: print only the number. Make a function for both of them (toCountryCode and toPhoneNo) that takes an Integer and throws an error if the integer is negative otherwise it creates the value.

If CountryCode is negative, the error should be "Negative country code" and if PhoneNo is negative, the error should be "Negative phone number" and you should follow these literally to pass the automatic testing.

Again, using the record syntax, define Phone type for phone numbers that has only one value constructor with fields

phoneType :: PhoneType,
countryCode :: CountryCode, (This time the type defined as above)
phoneNo :: PhoneNo. (This time the type defined as above)

Derive an instance for Eq and Ord for the record, but for Show make it "pretty-print" the infromation in this form: e.g. +358 123456789 (WorkLandline)

Now my take on the task:

data PhoneType = WorkLandline|PrivateMobile|WorkMobile|Other deriving (Read,Show,Eq)

newtype PlainString = PlainString String
instance Show PlainString where
  show (PlainString s) = s
--instance Num Int where
--   (*)=int_times
--   (+)=int_plus

data CountryCode = CountryCode
    {
        cCode :: Int
    } deriving (Read,Eq)
instance Show CountryCode where
    show (CountryCode a)=(show (PlainString "+")) ++ (show a)
instance Num CountryCode where 
    (*) a b=a*b 
    (+) a b=a+b 
    (-) a b=a-b
    fromInteger x=fromInteger x 

toCountryCode :: Int->CountryCode
toCountryCode ccode  
    | ccode<0=error "Negative country code"
    |otherwise = CountryCode ccode


data PhoneNo = PhoneNo
    {
        pNo :: Int
    } deriving (Read,Eq)
instance Show PhoneNo where
    show (PhoneNo a)=show a
instance Num PhoneNo where
    (*) a b=a*b
    (+) a b=a+b
    (-) a b=a-b
    fromInteger x= fromInteger x

toPhoneNo :: Int -> PhoneNo
toPhoneNo pno  
    | pno<0=error "Negative phone number"
    |otherwise = PhoneNo pno

data Phone = Phone
    {
        phoneType :: PhoneType,
        countryCode :: CountryCode,
        phoneNo :: PhoneNo
    } deriving (Read,Eq)
instance Show Phone where
    show (Phone a b c)=show a

makePhone :: PhoneType -> CountryCode  -> PhoneNo -> Phone
makePhone phonetype countrycode phoneno
    |otherwise = Phone phonetype countrycode phoneno

This version kinda workds with: makePhone Other 1 1 , which shows Other.

However, if i modify this to: show (Phone a b c)=show b or make sane show like asked in task - program hangs indefinitely. Same goes for show c

What do I do wrong?


Solution

  • Implementations like:

    instance Num CountryCode where 
        (*) a b = a*b 
        (+) a b = a+b 
        (-) a b = a-b
        fromInteger x = fromInteger x
    

    make not much sense, since you here define that you can add two CountryCodes together, by adding these together... This thus results in infite recursion.

    You can define addition, multiplication, etc. by unpacking the value wrapped in the CountryCode data constructor, perform the arithmetic, and then wrap it in a CountryCode data constructor:

    instance Num CountryCode where 
        CountryCode a * CountryCode b = CountryCode (a * b)
        CountryCode a + CountryCode b = CountryCode (a + b)
        CountryCode a - CountryCode b = CountryCode (a - b)
        fromInteger x = CountryCode (fromInteger x)

    The same happens with the instance Num PhoneNo.