在类型类中重载 Show 和 Num 会使执行无限期挂起

Overloading Show and Num in typeclass makes execution hang indefinitely

我正在对 Haskell 进行分配,并且几乎解决了它。感觉好像我错过了最后一步,但无法确定,我做错了什么。

首先是我的任务:

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)

现在我的任务是:

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

这个版本有点适用于: makePhone 其他 1 1 , 显示 其他.

但是,如果我将其修改为: 显示 (Phone a b c)=显示 b 或者按照任务中的要求使 show 正常 - 程序无限期挂起。同样适用于 show c

我做错了什么?

实施如:

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

没有多大意义,因为您在这里定义可以将两个 CountryCode 加在一起,通过将它们加在一起...因此导致无限递归。

您可以定义加法、乘法等,方法是解包包装在 CountryCode 数据构造函数中的值,执行算术运算,然后将其包装在 CountryCode 数据构造函数中:

instance Num CountryCode where 
    <strong>CountryCode</strong> a * <strong>CountryCode</strong> b = <strong>CountryCode</strong> (a * b)
    <strong>CountryCode</strong> a + <strong>CountryCode</strong> b = <strong>CountryCode</strong> (a + b)
    <strong>CountryCode</strong> a - <strong>CountryCode</strong> b = <strong>CountryCode</strong> (a - b)
    fromInteger x = <strong>CountryCode</strong> (fromInteger x)

instance Num PhoneNo也是如此。

您可以使用 GeneralizedNewtypeDeriving 派生以下实例,但它们必须是 newtype 才能起作用:

  • Show PlainString
  • Num CountryCode
  • Show PhoneNoNum PhoneNo

我建议使用 DerivingStrategies 明确说明您使用的是哪种推导方法:stock 使用 GHC 内置的推导机制,newtype 使用底层实例输入(Show StringShow IntNum Int)。

{-# Language DerivingStrategies         #-}
{-# Language GeneralizedNewtypeDeriving #-}

newtype CountryCode = CountryCode { cCode :: Int }
  deriving
  stock (Eq, Read)

  deriving
  newtype Num

newtype PlainString = PlainString String
  deriving
  newtype Show

newtype PhoneNo = PhoneNo { pNo :: Int }
  deriving
  stock (Eq, Read)

  deriving
  newtype (Num, Show)