在haskell中从笛卡尔3d转换为球形3d坐标系

时间:2010-11-10 12:22:42

标签: haskell coordinate-systems

我正在尝试将笛卡尔三维坐标系中的一个点转换为球形三维系统。

这是我到目前为止所得到的:

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

2 个答案:

答案 0 :(得分:6)

更一般地说,在Haskell中,参数通常不以“foo(x,y,z)”的形式编写。相反,我们写“foo x y z”。前者是合法的:它将参数包装成单个值(称为元组)并传递它,但它是不必要的。

错误消息来自

beta = atan2 (y, x).

由于库函数atan2的类型大致为

,因此失败
atan2 :: RealFloat a => a -> a -> a

这意味着对于任何类型“a”,它是“RealFloat”的实例(即“Float”和“Double”类型),函数“atan2”将其中两个作为参数并返回一个新参数。 “RealFloat a =&gt; ...”位表示在其余类型中,“a”可以是任何被声明为RealFloat类的实例的类型。 “浮动”和“双重”是这些类型的示例。因此,此功能的一种潜在类型是:

atan2 :: Double -> Double -> Double

然而,你所做的就是将它视为具有不同的类型:

atan2 :: (Double, Double) -> Double

这表示“atan2”采用单个参数,这是一个包含两个值的元组。类型检查器试图查看整个元组是否是“RealFloat”的实例(即我们可以用“atan2”类型替换“a”的类型之一),并发现它不是。所以它生成了一条错误消息,说明了这一点。

当你将隐式括号放回来时,“atan2 y x”语法和类型签名中的箭头实际上会发生什么。“ - &gt;” type运算符是右关联的,因此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的强大优势之一。

答案 1 :(得分:5)

更正后的代码:

radialDistance3D (x,y,z) = sqrt (x*x + 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

有两个错误,第一个是

radialDistance3D (x,y,z) = sqrt (x*2 + y*y + z*z)` 

应该是

radialDistance3D (x,y,z) = sqrt (x*x + y*y + z*z)

第二个是

beta  = atan2(y,x)  

应该是

beta = atan2 x y