Haskell 类型类定义,其函数取决于其他类型
Haskell还是个新手,我遇到了以下问题:Haskell 类型类定义,其函数取决于其他类型,haskell,typeclass,Haskell,Typeclass,Haskell还是个新手,我遇到了以下问题: class MixedRing b where (.+.) :: b -> b -> b (.*.) :: (Num a) => b -> a -> b (./.) :: (Num a) => b -> a -> b 我试图定义一些类型类来推广一系列函数,这些函数使用高斯消去法来求解线性方程组 给定一个线性系统 M x = k 元素m(i,j)\elem m的类型a可以不同于
class MixedRing b where
(.+.) :: b -> b -> b
(.*.) :: (Num a) => b -> a -> b
(./.) :: (Num a) => b -> a -> b
我试图定义一些类型类来推广一系列函数,这些函数使用高斯消去法来求解线性方程组
给定一个线性系统
M x = k
元素m(i,j)\elem m
的类型a
可以不同于x
和k
的类型b
。为了能够解决该系统,a
应该是Num
的一个实例,b
应该具有带b
的乘法/加法运算符,如下所示:
class MixedRing b where
(.+.) :: b -> b -> b
(.*.) :: (Num a) => b -> a -> b
(./.) :: (Num a) => b -> a -> b
现在,即使在这些运算符的最简单的实现中,我也会得到无法推导出a~Int。a是一个刚性类型变量
错误(让我们忘记/
,它需要分数
)
我已经阅读了一些关于类型类的教程,但我找不到任何指向实际错误的指针。您的实现不够多态 规则是,如果在类定义中编写
a
,则不能在实例中使用具体类型。因为实例必须符合类,并且类承诺接受任何a
,即Num
换言之:类变量正是必须在实例定义中用具体类型实例化的变量
您是否尝试过:
data Wrap a = W { get :: a }
请注意,一旦
Wrap a
是一个实例,您仍然可以将其与只接受Wrap Int
的函数一起使用,例如:
class (Num a) => MixedRing a b where
(.+.) :: b -> b -> b
(.*.) :: b -> a -> b
(./.) :: b -> a -> b
您需要MultiParamTypeClasses
扩展名
顺便说一句,在我看来,你试图建模的数学结构实际上是模块,而不是环。对于上面给出的类型变量,可以说
b
是一个a
-模块。让我们看看您必须为(.*)
提供的实现类型,以使Wrap
成为混合的一个实例。将方法类型中的Wrap
替换为b
,将产生
(.*.) :: Num a => Wrap -> a -> Wrap
由于Wrap
与Int
同构,因此不必考虑使用Wrap
和get
进行包装和展开,让我们将目标简化为找到
(.*.) :: Num a => Int -> a -> Int
(你看到这并没有让挑战变得更容易或更难,不是吗?)
现在,请注意,这样的实现将需要能够对碰巧位于type类Num
中的所有类型a
进行操作。(这就是这种类型中的类型变量所表示的:通用量化。)注意:这与说您的实现本身可以选择要操作的a
不同(实际上,这是相反的);然而,这就是您在问题中的建议:应该允许您的实现选择Int
作为a
的选择
现在,当您想用(*)
类型Int
的(*)
来实现这个特定的(*)
时,我们需要以下形式的东西
n .*. s = n * f s
与
我想不出一个函数能够以一种有意义的方式将任意的Num
-typea
转换为Int
。因此,我要说的是,没有任何有意义的方法可以使Int
(因此,Wrap
)成为混合的一个实例;也就是说,实例的行为与您可能期望的不同。已经有一个包定义了这个类:您可以在那里看一看。是的,我已经尝试过这个-有限制和没有限制instance(Num a)=>MixedRing(Wrap a)其中
-没有帮助。但这是因为您实现了。*.,请参阅dblhelix
注释。不知道有多参数类型的类,这是有效的。你是对的,当然,模块是正确的术语。物理学家,这里不是数学家,近似值就足够了;)很好的解释。实际上有两个错误:第一,不能在实例定义中实例化a(来自类定义)和b)方法。*。实现的是导致b=a,因此与。*的类型相矛盾。在课堂上给出。谢谢你的精彩解释。连同其他答案以及指向VectorSpace
包的链接,这澄清了问题。
f :: Num a => a -> Int