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.
Peu importe, je l'ai eu :) C'est atan2 yx, pas atan2 (y, x) – anybody
Ne devrait pas 'radialDistance3D (x, y, z)' être '= sqrt (x * x + y * y + z * z) ', pas' = sqrt (x * 2 + y * y + z * z) '!? – adamse
Puisque vous l'avez déjà compris, pourquoi ne pas écrire une réponse sur SO? –