我有一个用于 Haskell 中多项式的数据类型 Polynomial r 和一个 Ring 实例。 (class Ring r where plus :: r -> r -> r ; times :: r -> r -> r ; negative :: r -> r ; zero :: r ; one :: r
——它只是 Num 的简化版本)。
现在我可以定义一个多项式,例如 gauss = x^2 + 1
或 eisenstein = 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
和 zero
.所以我把它改成了data Quotient p = Quot p (Maybe p)
我想我有一个使用它的工作实现,但你永远不知道 plus
将起作用(它至少需要一个 Just
,如果有两个,它们必须相同)。
是否有任何类型安全(我的意思是不使用不安全函数)的方式来在 haskell 中进行编程?我很困惑。谢谢!
最佳答案
也许你可以用索引或标签来增加你的多项式类型?如果我理解正确,您的正常模块将类似于:
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
的负担实例。我认为最终它会是相似的,如果比这种方法稍微优雅一点的话。
关于haskell - 定义不想定义的数据类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4612830/