Haskell还是新手,我已经碰到了以下内容:
我试图定义一些类型类来概括一堆使用高斯消元法求解线性方程组的函数。
给定一个线性系统
M x = k
元素a
的类型m(i,j) \elem M
可能与b
和x
的类型k
不同。为了能够解决系统问题,a
应该是Num
的实例,而b
应该有b
的乘法/加法运算符,如下所示:
class MixedRing b where
(.+.) :: b -> b -> b
(.*.) :: (Num a) => b -> a -> b
(./.) :: (Num a) => b -> a -> b
现在,即使在这些运算符的最简单实现中,我也会遇到Could not deduce a ~ Int. a is a rigid type variable
错误(让我们忘记需要./.
的{{1}})
Fractional
我已经阅读了几个关于类型类的教程,但我找不到指向实际出错的指针。
答案 0 :(得分:10)
让我们看看您必须为(.*.)
提供Wrap
MixedRing
实例的实施类型。在方法类型中用Wrap
代替b
会产生
(.*.) :: Num a => Wrap -> a -> Wrap
由于Wrap
与Int
同构,并且不必考虑使用Wrap
和get
进行包装和解包,让我们减少查找
(.*.) :: Num a => Int -> a -> Int
(你知道这不会让挑战变得更容易或更难,不是吗?)
现在,请注意,这样的实现需要能够对类型类a
中恰好位于的所有类型Num
进行操作。 (这就是这种类型的类型变量表示:通用量化。)注意:这说明你的实现本身可以选择a
进行操作,这是不一样的(实际上是相反的);但这似乎是您在问题中建议的:应该允许您的实施选择Int
作为a
的选择。
现在,由于您希望针对类型(.*.)
的值(*)
实现此特定Int
,我们需要一些形式
n .*. s = n * f s
与
f :: Num a => a -> Int
我无法想象一个能够以有意义的方式从仲裁Num
- 类型a
转换为Int
的函数。因此,我要说,没有任何有意义的方法可以使Int
(以及Wrap
)成为MixedRing
的实例;也就是说,实例的行为并不像你希望的那样。
答案 1 :(得分:6)
如下:
class (Num a) => MixedRing a b where
(.+.) :: b -> b -> b
(.*.) :: b -> a -> b
(./.) :: b -> a -> b
您需要MultiParamTypeClasses
扩展名。
顺便说一句,在我看来,您尝试建模的数学结构实际上是模块,而不是环。使用上面给出的类型变量,可以说 b
是a
- 模块。
答案 2 :(得分:2)
您的实现不够多态。
规则是,如果在类定义中编写a
,则不能在实例中使用具体类型。因为实例必须符合类和承诺接受任何a
Num
的类。
换句话说:正是类变量必须在实例定义中使用具体类型进行实例化。
你试过了吗?
data Wrap a = W { get :: a }
请注意,Wrap a
是一个实例,您仍然可以将其与仅接受Wrap Int
的函数一起使用。