分数坐标newtype

时间:2016-07-21 16:45:25

标签: haskell newtype

我正在制作一些关于2D几何的基本模块,我决定用新类型包装坐标。这样我可以很容易地从极坐标(newtype Xy = Xy(Float,Float))中分辨出笛卡尔坐标(newtype Ra=Ra(Float,Float)),也可能是复数;还要使它们成为NumFractional的实例,这样我就可以重载运算符。

但是,它们必须被定义为一对Float还是一对Double?在一些三角函数中,Double在精度方面可能明显更好;我为Xy新类型编写的许多函数我希望它们尽可能通用。 那么有没有办法用一对Fractional类的数字来创建一个新类型?

此外,由于我发现编写Xy (0,0)而不是简单地(0,0)有点麻烦,我创建了·运算符:

(·) a b = Xy (a,b)

但它似乎优先于其余部分,因此3+4·2+1被评估为3+(Xy (4,2))+1。 它也不会对函数声明,lambda表达式等有帮助......我仍然需要编写\Xy (a,b)->

感谢。

2 个答案:

答案 0 :(得分:5)

您可以在新类型中使用类型参数:

newtype Xy n = Xy (n, n)

然后你可以编写适用于Fractional类中的任何对的函数:

foo :: Fractional n => Xy n -> Xy n -> ...

如果您的操作只对双打有意义,您也可以使用Xy Double等特定类型。

不幸的是,您不能只重复使用元组语法((a, b)),但如果您编写的类型包含两个字段而不是包装一对,则它是可管理的:

data Xy n = Xy n n

现在您可以将Xy a b写为值或模式。您甚至可以将其设为记录以获得方便的字段语法:

data Xy n = Xy { x, y :: n }

这与以前的版本一样,但允许您使用xy作为函数(即x :: Xy n -> n)和模式。

答案 1 :(得分:3)

IMO你可能只是使用Double,总是很难烘焙。在x86-64处理器上,Float没有给你带来真正的好处 - 它需要相同的内存(因为每个值都需要一个64位指针来引用它),不会更快(甚至可能需要)额外的对齐开销) - 没有意义。 Double很好,速度快,通常可以为争取最佳精确度。

它肯定很多比存储类似OO的分数类的通用实例更好 - 这种多态性会导致相当大的重载。幸运的是,Haskell也真的避开了storing polymorphic values

我也不认为将Xy定义为仿函数在概念上是明智的,即Tikhon Jelvis建议的参数多态的类型。虽然这绝对是一种有效的方法,并且可以提供非常好的性能(这是linear library的工作方式),但这会错过传播的内容。数学向量最重要的是不是数字元组,而是a quantity that has both a direction and a magnitude。这种向量的实际坐标应仅被视为实现细节。

您也不想制作Num等类的2D事物实例。这些类适用于numbers - 可以通过规范添加,减去和相乘的数量。你不能将矢量相乘,至少不能再给你一个矢量。向量的正确类是VectorSpace,而不是Num

应该注意的是packed Float数组确实可以节省大量内存,如果使用现代vectorised processor instructions,它们也可以实际上要快得多。但是这些优化在您讨论单个元组的级别上并不是真正可用的。