在Haskell中键入实例

在Haskell中键入实例,haskell,Haskell,回想一下,在数学中,magma是一个带有二进制运算的集合。我正在Haskell中定义一个magma类型类: class Magma a where multiplication :: a -> a -> a instance Magma [a] where multiplication x y = x ++ y instance (Num a) => Magma a where multiplication x y = x + y 当然,任何类型的

回想一下,在数学中,magma是一个带有二进制运算的集合。我正在Haskell中定义一个magma类型类:

class Magma a where
    multiplication :: a -> a -> a
instance Magma [a] where
    multiplication x y = x ++ y
instance (Num a) => Magma a where
    multiplication x y = x + y
当然,任何类型的带有连接运算符的列表都会形成一个magma,事实上,Haskell中有以下工作:

class Magma a where
    multiplication :: a -> a -> a
instance Magma [a] where
    multiplication x y = x ++ y
instance (Num a) => Magma a where
    multiplication x y = x + y
类似地,带加法的实数形成magma,但以下实例声明在Haskell中不起作用:

class Magma a where
    multiplication :: a -> a -> a
instance Magma [a] where
    multiplication x y = x ++ y
instance (Num a) => Magma a where
    multiplication x y = x + y
您能解释一下为什么第一个实例声明工作得很好,而第二个带有类型约束的声明却不工作吗? (我正在使用ghc。)

您将需要以下语言扩展:

{-# LANGUAGE FlexibleInstances, UndecidableInstances #-}

class Magma a where
    multiplication :: a -> a -> a

instance (Num a) => Magma a where
    multiplication x y = x + y
或者,使用新类型:

newtype Sum a = Sum { getSum :: a }

instance (Num a) => Magma (Sum a) where
    multiplication x y = Sum $ getSum x + getSum y

另外,请注意,您的Magma类型类与有很多共同之处,特别是addition下的Num实例与重叠


您还可以在乘法下定义数字类型的实例,如中所示

请注意,如果您添加了
不可判定实例
FlexibleInstances
语言扩展,那么它就可以工作了。感谢您的评论和回答,但您能否更详细地描述一下Haskell的哪些语言机制阻止我(以及为什么)做出这样的实例声明?(事实上,它可以与上述语言扩展一起工作,但为什么没有它们它就不能工作?我对此感兴趣是出于理论原因,而不是实际原因。)问题是实例声明(默认情况下)的形式必须是
instance context=>C(t a1..an)
where
a1
。。,
a
出现在
contentx
中,
T
是一个类型构造函数。在您的情况下,您的声明的形式是
instance context=>ca
,您缺少
T
!假设我添加了
instance Num[Int]
,因为我可能喜欢执行逐点操作(即使这对于列表来说不是个好主意)。现在,
乘法[2][3]
应该是什么<代码>[2,3]或
[5]
?如果我想要一个带有
*
的magma呢?@Bakuriu谢谢,看来你的评论是正确的答案!简单地说,第二个声明不起作用,因为它在语法上不正确!类型构造函数“T”是必需的。我认为这很奇怪,因为不编写类型构造函数可能会被解释为一个微不足道的“标识”构造函数。为什么要选择这样的设计,为什么要强制使用构造函数?Bakuriu我最喜欢你的评论/回答,如果你能添加任何内容,请随意写下一个合适的回答,这样我就可以接受。
newtype
和Kmett的建议+1。如果以后需要其他实例,则第一个实例将需要重叠实例(如果不需要,只需定义
乘法::Num a=>…
并避免使用magma类)。最好避免重叠的实例。我认为
multiply xy=Sum$getSum x+getSum y
也可以编写
multiply=liftA2(+)