2010-11-10 29 views
2

J'essaie de convertir un point en système de coordonnées 3d cartésien en un système 3d sphérique.Conversion d'un système de coordonnées 3d cartésien en sphère 3d en haskell

C'est ce que je suis arrivé à ce jour:

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 charge le code, mais lorsque je tente de l'exécuter avec

cartesian3DToPolar3D (1.0,2.0,3.0)

Je reçois:

<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) 

Ce qui n'est pas utile. Que se passe-t-il?

formules de conversion sont de http://en.wikipedia.org/wiki/Spherical_coordinate_system#Cartesian_coordinates

+0

Peu importe, je l'ai eu :) C'est atan2 yx, pas atan2 (y, x) – anybody

+3

Ne devrait pas 'radialDistance3D (x, y, z)' être '= sqrt (x * x + y * y + z * z) ', pas' = sqrt (x * 2 + y * y + z * z) '!? – adamse

+0

Puisque vous l'avez déjà compris, pourquoi ne pas écrire une réponse sur SO? –

Répondre

5

code corrigé:

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 

Il y avait deux erreurs, d'abord était dans

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

qui devrait être

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

le second était

beta = atan2(y,x) 

qui devrait être

beta = atan2 x y 
+0

Marquer comme réponse –

+0

Vous pouvez accepter votre propre réponse dans 2 jours :) – anybody

6

Plus généralement, dans les arguments Haskell ne sont pas normalement écrits sous la forme "foo (x, y, z)". Au lieu de cela, nous écrivons "foo x y z". Le premier est légal: il enveloppe les arguments en une seule valeur (appelée un tuple) et le transmet, mais ce n'est pas nécessaire.

Le message d'erreur est venue de la ligne

beta = atan2 (y, x). 

Cela a échoué en raison du type de la fonction de bibliothèque atan2, qui est à peu près

atan2 :: RealFloat a => a -> a -> a 

Cela signifie que pour tout type « a » qui est une instance de "RealFloat" (ie les types "Float" et "Double"), la fonction "atan2" en prend deux comme arguments et en retourne une nouvelle. Le bit "RealFloat a => ..." indique que dans le reste du type "a" peut être n'importe quel type qui est déclaré être une instance de la classe RealFloat. "Float" et "Double" sont des exemples de ces types. Donc, un type potentiel pour cette fonction est:

atan2 :: Double -> Double -> Double 

Cependant ce que vous avez été le traiter comme si elle avait un autre type:

atan2 :: (Double, Double) -> Double 

Cela dit que « atan2 » prend un seul argument qui est un tuple contenant deux valeurs. Le vérificateur de type a essayé de voir si ce tuple entier est une instance de "RealFloat" (c'est-à-dire l'un des types que nous pouvons remplacer "a" dans le type "atan2"), et a trouvé que ce n'est pas le cas. Donc, il a généré un message d'erreur le disant.Ce qui se passe réellement dans la syntaxe "atan2 yx", et dans les flèches dans la signature de type, est révélé lorsque vous remettez les parenthèses implicites. L'opérateur de type "->" est associatif, donc le type de atan2 est en fait:

atan2 :: Double -> (Double -> Double) 

(Note: pour plus de simplicité je quitte la entreprise « RealFloat a ».) Cela dit que « atan2 » prend un argument et retourne une nouvelle fonction qui attend le second argument .

Maintenant, mettons les parenthèses implicites dans l'appel. L'application de fonction est laissée associative, donc la définition de "beta" ressemble à ceci;

beta = (atan2 x) y 

Conformément à la règle d'évaluation crochets de l'intérieur, cela vaut la fonction « atan2 » à « x » et obtient une nouvelle fonction à la suite, qui est ensuite appliqué à « y » donner « bêta » Par conséquent. Voyez comment le type et l'expression se reflètent l'un l'autre?

Ce n'est pas seulement un truc théorique: je pourrais écrire quelque chose comme

myBeta = atan2 x 
... 
beta = myBeta y 

Ou encore

betas = map myBeta ys 

où « YS » et « bêtas » sont des listes de valeurs. Être capable de faire quelque chose comme ça est l'une des grandes forces de Haskell.