创建 Semigroup 的参数化数据类型实例

Make a parametrized data type instance of Semigroup

我想使数据类型Moneda成为Semigroup的一个实例,并将关联操作实现为+。我很难正确理解它。

我找到的工作解决方案如下:

data Moneda a = RON Double | EUR Double deriving (Show)

instance Num a => Num (Moneda a) where
    (RON x) + (RON y) = RON (x + y)
    (RON x) + (RON y) = RON (x + y)

instance Semigroup (Moneda a) where
    (<>) = (+)

我不明白为什么下面的方法会失败,以及如何在不使 Moneda 成为 Num 实例的情况下使其工作。

data Moneda a = RON a | EUR a deriving (Show)

instance Semigroup (Moneda a) where
    (<>) (RON a) (RON b) = (RON a+b) -- fails, please see error below
vs 
    (<>) (RON a) (RON b) = (RON a) -- works but doesn't help me because I need the a+b sum  

-- cannot construct the infinite type: a ~ Moneda a 
-- In the second argument of `(+)', namely `b'

您收到的错误是因为您在 (<>) 的实现中尝试将类型 Moneda a 的值添加到类型 a 的值。那就是你写的 (RON a+b) 解析为 (RON a) + b (因为 function/constructor 应用程序绑定比加法强)。您可能打算将 RON (a + b) 写成:

data Moneda a = RON a | EUR a deriving (Show)

instance Semigroup (Moneda a) where
  (<>) (RON a) (RON b) = RON (a + b)

但这也行不通,因为它需要在您应用的类型上定义附加项 Moneda。因此,为了使您的定义有意义,您需要将类型参数 a 的实例化限制为 Num:

中的类型
data Moneda a = RON a | EUR a deriving (Show)

instance Num a => Semigroup (Moneda a) where
  RON a <> RON b = RON (a + b)
  EUR a <> EUR b = EUR (a + b)

例如:

> RON 2 <> RON 3
RON 5

请注意,(<>) 的这个定义只是部分的。它不考虑将使用 RON 构建的值添加到使用 EUR:

构建的值
> RON 5 <> EUR 7
*** Exception: Main.hs:(4,3)-(5,30): Non-exhaustive patterns in function <>

因此,您仍然需要编写处理这些情况的代码。