如何匹配类型类实例中的刚性类型?

时间:2009-12-22 15:13:28

标签: haskell numeric typeclass

我想我会尝试在不同维度的矢量上建模一些数值积分,并认为类型类是要走的路。我需要一些东西来定义两个值之间的差异,并通过乘数(得到导数)来缩放它,以及能够获取距离函数。

到目前为止,我有:

class Integratable a where
    difference :: a -> a -> a
    scale :: Num b => a -> b -> a
    distance :: Num b => a -> a -> b

data Num a => Vector a = Vector1D a | Vector2D a a

instance Num a => Integratable (Vector a) where
    difference (Vector1D x1) (Vector1D x2) = Vector1D (x1 - x2)
    scale (Vector1D x) m = Vector1D (x * m)
    distance (Vector1D x1) (Vector1D x2) = x1 - x2
    difference (Vector2D x1 y1) (Vector2D x2 y2) = Vector2D (x1 - x2) (y1 - y2)
    scale (Vector2D x y) m = Vector2D (x * m) (y * m)
    distance (Vector2D x1 y1) (Vector2D x2 y2) = sqrt((x1-x2)*(x1-x2)
                                                      + (y1-y2)*(y1-y2))

不幸的是,这里有一些问题我还没弄清楚如何解决。首先,scale函数会出错。 GHC无法判断mx是否兼容,因为在一种情况下在实例中给出了严格类型限制Num,在另一种情况下在Vector类型中给出了x类型case ...有没有办法指定mx是同一类型?

(事实上我意识到,即使mNum都是Num,它们也可能不是相同 Num。我可以指定这个吗?如果我无法用Double解决这个问题,使用distance会很好,但我宁愿保持一般。)

Num存在类似问题。尝试指定返回类型为a失败,因为它无法在实例定义中告知b将包含与{{1}}兼容的值。

2 个答案:

答案 0 :(得分:1)

编辑:现在我觉得来自HaskellWiki的functional dependencies上的文章提供了我能找到的最佳形式的关键信息,所以我建议改为阅读我的答案在这里。不过,我并没有删除剩下的内容,因为它清楚地表明了(我希望)为什么FD在这里很有用。


除了Dave指出的定义问题分组......

  

(事实上我意识到,即使xm都是Num,它们也可能不是相同 Num。我可以指定这个吗?如果我无法用Num解决这个问题,使用Double会很好,但我宁愿保持一般。)

实际上,这是主要问题。你不能将Integer乘以Float。实际上,您需要xm的比例属于同一类型。

此外,距离也会出现类似的问题,sqrt需要Floating参数的额外复杂性。所以我猜你也需要在某个地方提到它。 (最有可能在实例上,我猜)。

编辑:好的,由于sqrt仅适用于Floating值,因此您可以为那些将Float转发为Double的类型滚动到Scalable在需要时。

另一个想法涉及使用类型类data Vector a = Vector1D a | Vector2D a a deriving (Show) class Scalable a b | a -> b where scale :: a -> b -> a instance (Num a) => Scalable (Vector a) a where scale (Vector1D x) m = (Vector1D (x * m)) scale (Vector2D x y) m = (Vector2D (x * m) (y * m))

Scalable

这在{{1}}的定义中使用了所谓的函数依赖。事实上,我试图记住它的语法,我发现this link ...所以我想你应该忽视我的低级尝试,并在那里阅读质量信息。 ; - )

我认为你应该能够用它来解决原来的问题。

答案 1 :(得分:0)

要修复第二个错误,我认为您需要在实例声明中重新排序您的定义。首先得到difference的两个等式,然后是scale的等式,然后是distance的等式。