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

标签 haskell

我是新人,从书中学习:

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

我想我可以写一个 func 来使用 +,例如:Monday + 1 = Tuesday

所以:

:{                           
(+) :: 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。但是这个新的 (+) 函数返回一个 Day! Enum 的多态版本可以工作,因为 Int 有一个 Enum 实例,所以 (+) 可以是用于两种类型。

要解决这个问题,您可以简单地为该操作指定一个新名称,而不是隐藏 (+)。或者,当您想使用新的 (+) 时,您可以通过编写 (y Prelude.+ 1) 来明确递归调用。

关于haskell - 如何为自定义数据类型定义 (+) 函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70528861/

相关文章:

haskell - 具有不同幺半群结构的松散幺半群仿函数

list - Haskell - 将列表分成两个总和最接近的子列表

haskell - 翻转也许并列出

haskell - 有没有办法在 Haskell 中将多态函数应用于具有不同参数类型的多个对象?

haskell - 在 Haskell 中,当我们使用 do block 时,它如何确定要使用哪个 monad?

haskell - 如何获得到静态目录(不是静态文件)的类型安全路由?

haskell - 如何为自定义新类型派生 PersistField?

haskell 从列表列表中删除所有出现的给定值

haskell - 清理快照路由处理程序 (Haskell)

haskell - 管道广播