如何为自定义数据类型定义 (+) 函数?

How to define (+) function for custom data type?

我是新人,正在学习书本:

data Day 
  = Monday 
  | Tuesday 
  | Wednesday 
  | Thursday 
  | Friday 
  | Saturday 
  | Sunday 
  deriving (Eq, Ord, Show, Read, Bounded, Enum)

我想我可以写一个 func 来使用 +,例如:星期一 + 1 = 星期二

所以:

:{                           
(+) :: Day -> Int -> Day     
(+) x y                      
  | y>0 = (+) (succ x) (y-1) 
  | y<0 = (+) (pred x) (y+1) 
  | y==0 = x                 
:}   

但是ghci说它有错误:

? Couldn't match expected type ‘Int’ with actual type ‘Day’
? In the second argument of ‘(+)’, namely ‘(y + 1)’
  In the expression: (+) (pred x) (y + 1)
  In an equation for ‘+’:
      (+) x y
        | y > 0 = (+) (succ x) (y - 1)
        | y < 0 = (+) (pred x) (y + 1)
        | y == 0 = x

我不知道为什么,但我尝试了另一个:

:{                                
(+) :: (Enum a) =>  a -> Int -> a 
(+) x y                           
  | y>0 = (+) (succ x) (y-1)      
  | y<0 = (+) (pred x) (y+1)      
  | y==0 = x                      
:}                                

效果不错,比如:

ghci> Monday + 1     
Tuesday              
ghci> Monday + 3     
Thursday             
ghci> Thursday + (-2)
Tuesday              

但是我还是不知道Day -> Int -> Day有什么问题。

定义名为 (+) 的函数时,您正在隐藏 Prelude 的加法函数。在 (+) :: Day -> Int -> Day 的正文中,您计算​​ (y + 1),期望 Int。但是这个新的(+)函数returns一个DayEnum 的多态版本有效,因为 Int 有一个 Enum 实例,因此 (+) 可以用于两种类型。

要解决这个问题,您可以简单地为该操作指定一个新名称,而不是隐藏 (+)。或者,当您想使用新的 (+) 和原始的 (y Prelude.+ 1).

时,您可以在递归调用中明确表示