我正在尝试将笛卡尔3d坐标系中的点转换为球面3d系统。
这是我到目前为止所得到的:
radialDistance3D (x,y,z) = sqrt (x*2 + y*y + z*z)
cartesian3DToPolar3D (x,y,z) = (r,alpha, beta)
where r = radialDistance3D (x,y,z)
alpha = acos(z/r)
beta = atan2(y,x)
Ghci加载了代码,但是当我尝试使用
cartesian3DToPolar3D(1.0,2.0,3.0)
我得到:
<interactive>:1:0:
No instance for (RealFloat (t, t))
arising from a use of `cartesian3DToPolar3D'
at <interactive>:1:0-33
Possible fix: add an instance declaration for (RealFloat (t, t))
In the expression: cartesian3DToPolar3D (1.0, 2.0, 3.0)
In the definition of `it':
it = cartesian3DToPolar3D (1.0, 2.0, 3.0)
这没有帮助。到底是怎么回事?
转换公式来自http://en.wikipedia.org/wiki/Spherical_coordinate_system#Cartesian_coordinates
最佳答案
通常,在Haskell中,参数通常不以“ foo(x,y,z)”的形式编写。相反,我们写“ foo x y z”。前者是合法的:它将参数包装为单个值(称为元组)并将其传递,但这是不必要的。
错误消息来自该行
beta = atan2 (y, x).
由于库函数atan2的类型而失败,该函数大致
atan2 :: RealFloat a => a -> a -> a
这意味着对于作为“ RealFloat”实例的任何类型“ a”(即类型“ Float”和“ Double”),函数“ atan2”都将其中两个作为参数并返回一个新值。 “ RealFloat a => ...”位表示,在类型“ a”的其余部分中,可以是声明为RealFloat类的实例的任何类型。 “ Float”和“ Double”是这些类型的示例。因此,此功能的一种潜在类型是:
atan2 :: Double -> Double -> Double
但是,您所做的是将其视为具有其他类型:
atan2 :: (Double, Double) -> Double
这表示“ atan2”采用单个参数,该参数是包含两个值的元组。类型检查器试图查看整个元组是否是“ RealFloat”的实例(即我们可以用“ atan2”类型替换“ a”的类型之一),但事实并非如此。因此它生成了一条错误消息,说明是这样。
将隐式括号放回去时,将揭示“ atan2 yx”语法和类型签名中的箭头实际发生的情况。“->”类型运算符是右关联的,因此atan2的类型为其实:
atan2 :: Double -> (Double -> Double)
(注意:为简单起见,我省去了“ RealFloat a”业务。)这表明“ atan2”接受一个参数并返回一个新函数,该函数需要第二个参数。
现在,让隐式括号放入通话中。函数应用程序是左关联的,因此“ beta”的定义如下所示;
beta = (atan2 x) y
遵循从内到外评估方括号的规则,这会将函数“ atan2”应用于“ x”,并得到一个新函数,然后将其应用于“ y”,从而得出“ beta”。看看类型和表达式如何相互镜像?
这不仅是理论上的把戏,我可以写一些类似的东西
myBeta = atan2 x
...
beta = myBeta y
甚至
betas = map myBeta ys
其中“ ys”和“ betas”是值列表。能够做这样的事情是Haskell的一大优势。
关于haskell - 在Haskell中将笛卡尔3d坐标转换为球面3d坐标系,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/4144403/