首页 > 解决方案 > 如何向 Haskell 中的现有 Type 类添加新函数?

问题描述

我目前正在尝试了解 Haskell 类型类。在创建了下面的简单示例并看到它有效之后......

data MyMaybe a = MyNothing | MyJust a
    deriving(Show)

class IncreaseByOne a where
    addOne :: a -> a

instance (Num a) => IncreaseByOne (MyMaybe a) where
    addOne  MyNothing = (MyNothing)
    addOne (MyJust x) = (MyJust (x+1))

问我自己:是否可以将函数addOne添加到现有的 Type-Class Num。所以所有的数字都可以使用函数addOne。就像是:

instance IncreaseByOne Num where
    addOne x = x+1 
    

标签: haskelltypeclass

解决方案


好吧,您原则上可以编写如下实例

{-# LANGUAGE UndecidableInstances #-}
instance (Num a) => IncreaseByOne a where
  addOne x = x+1     -- or `addOne = (+1)`

-XUndecidableInstances不是一个真正的问题,但问题是这个实例与您可能想要声明的任何其他实例重叠MyMaybe,特别是与您的实例重叠。出现问题的原因是原则上没有什么能阻止你也有,也许只是稍后在更下游的模块中,

instance Num a => Num (MyMaybe a) where ...

然后两者Num a => IncreaseByOne a适用Num a => IncreaseByOne (MyMaybe a)

GHC可以做重叠的实例,但这通常是个坏主意。我建议您改为为所有相关的具体类型写出简短的实例。为了使这个更加简洁,您可以有一个基于以下内容的默认实现Num

{-# LANGUAGE DefaultSignatures #-}

class IncreaseByOne a where
  addOne :: a -> a
  default addOne :: Num a => a -> a
  addOne = (+1)

instance (Num a) => IncreaseByOne (MyMaybe a) where
  addOne = fmap (+1)   -- `MyMaybe` _should_ have a `Functor` instance!

instance IncreaseByOne Int       -- note no instance body is needed,
instance IncreaseByOne Integer   -- because the default implementation
instance IncreaseByOne Double    -- applies

推荐阅读