2

我正在尝试将笛卡尔 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

4

2 回答 2

6

更一般地说,在 Haskell 中,参数通常不写成“foo (x,y,z)”的形式。相反,我们写“foo xy 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 y x”语法和类型签名中的箭头实际上发生了什么。“->”类型运算符是右关联的,因此 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 的一大优势。

于 2010-11-10T18:09:15.000 回答
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
于 2010-11-10T12:54:27.440 回答