定义不想定义的数据类型

时间:2011-01-06 07:42:28

标签: haskell types typeclass

我有一个数据类型Polynomial r用于Haskell中的多项式,以及一个Ring实例。 (class Ring r where plus :: r -> r -> r ; times :: r -> r -> r ; negative :: r -> r ; zero :: r ; one :: r - 它只是Num的简化版本。)

现在我可以定义一个多项式,如gauss = x^2 + 1eisenstein = x^2 + x + 1,然后在“多项式整数/(高斯)”中为高斯整数或“多项式整数/(爱森斯坦)”用于爱森斯坦整数。这就是问题所在,我在引号中写道,因为它不是真正的数据类型,我无法弄清楚如何定义它。

我首先尝试做data Quotient p = Quot p p这样的事情,然后举例来说我们会plus (Quot a i) (Quot b i') | i == i' = Quot (plus a b) i当然这已经非常糟糕但是甚至无法定义one和{{1 }}。所以我将其更改为zero并且我认为我有一个有效的实现,但你永远不知道data Quotient p = Quot p (Maybe p)是否有用(它至少需要一个plus,如果有的话两个他们必须是一样的。)

是否有任何类型安全(我的意思是不使用不安全的函数)方法在haskell中编程?我很难过。谢谢!

2 个答案:

答案 0 :(得分:5)

也许您可以使用索引或标记来扩充多项式类型?如果我理解正确,你的正常模块将是:

data Poly r = Poly r

class Ring r where
  plus :: r -> r -> r
  times :: r -> r -> r

instance Ring (Poly Integer) where
  plus (Poly x) (Poly y) = Poly (x + y)
  times (Poly x) (Poly y) = Poly (x * y)

gauss :: Poly Integer
gauss = Poly 1

eins :: Poly Integer
eins = Poly 2

并且您希望能够安全地区分环的两个“子类型”。也许您可以将它们标记为:

newtype PolyI i r = PolyI r

instance Show r => Show (PolyI i r) where
  show (PolyI p) = show p

instance Ring (PolyI i Integer) where
  plus (PolyI x) (PolyI y) = PolyI (x + y)
  times (PolyI x) (PolyI y) = PolyI (x * y)

我们的Ring实例现在需要一个额外的类型参数i,我们可以通过使用简单的非构造函数类型来创建它。

data Gauss
data Eins

然后我们只用索引作为参数创建特定的多项式:

gaussI :: PolyI Gauss Integer
gaussI = PolyI 11

einsI :: PolyI Eins Integer
einsI = PolyI 20

使用上面的Show实例,我们得到以下输出:

*Poly> plus einsI einsI
40

然后

*Poly> plus einsI gaussI

Couldn't match expected type `Eins' with actual type `Gauss'
Expected type: PolyI Eins Integer
  Actual type: PolyI Gauss Integer
In the second argument of `plus', namely `gaussI'

这是你想要的吗?

在对newtype的问题发表评论后

修改,我认为如果您使用NewtypeDeriving来减轻重新实施的负担,这也可能是一个优雅的解决方案Poly Integer个实例。我认为最终会有类似的,如果比这种方法稍微优雅一点。

答案 1 :(得分:1)

implicit configurations论文(cabalized here)使用 Z 的商数作为示例;它应该直接适应多项式环(除非我遗漏了什么)。

编辑:不是说隐式配置本身是直截了当的,远非它;) - 只是修改。