我想我会尝试在不同维度的矢量上建模一些数值积分,并认为类型类是要走的路。我需要一些东西来定义两个值之间的差异,并通过乘数(得到导数)来缩放它,以及能够获取距离函数。
到目前为止,我有:
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无法判断m
和x
是否兼容,因为在一种情况下在实例中给出了严格类型限制Num
,在另一种情况下在Vector
类型中给出了x
类型case ...有没有办法指定m
和x
是同一类型?
(事实上我意识到,即使m
和Num
都是Num
,它们也可能不是相同 Num
。我可以指定这个吗?如果我无法用Double
解决这个问题,使用distance
会很好,但我宁愿保持一般。)
Num
存在类似问题。尝试指定返回类型为a
失败,因为它无法在实例定义中告知b
将包含与{{1}}兼容的值。
答案 0 :(得分:1)
编辑:现在我觉得来自HaskellWiki的functional dependencies上的文章提供了我能找到的最佳形式的关键信息,所以我建议改为阅读我的答案在这里。不过,我并没有删除剩下的内容,因为它清楚地表明了(我希望)为什么FD在这里很有用。
除了Dave指出的定义问题分组......
(事实上我意识到,即使
x
和m
都是Num
,它们也可能不是相同Num
。我可以指定这个吗?如果我无法用Num
解决这个问题,使用Double
会很好,但我宁愿保持一般。)
实际上,这是主要问题。你不能将Integer
乘以Float
。实际上,您需要x
和m
的比例属于同一类型。
此外,距离也会出现类似的问题,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
的等式。