/ / Erreur de correspondance de type Haskell - haskell

Erreur de correspondance de type Haskell - haskell

J'ai défini deux types de synonymes comme suit:

type Potential = Float
type Label = String
type LabelSet = [String]

De plus, j'ai défini le type et le type de synonyme suivant:

data VariableNode = VariableNode Label Potential LabelSet
type PGM = [VariableNode]

Enfin, la fonction suivante pour construire un graphique:

makePGM :: [((Label, Potential), LabelSet)] -> PGM
makePGM (x:xs) = (VariableNode (fst . fst x) (snd . fst x) (snd x)) : makePGM xs
makePGM [] = []

Dans la fonction ci-dessus, une liste de tuples est fournie où le premier élément du tuple est un autre tuple et le second une liste, selon la signature de type des fonctions.

Je suis nouveau sur Haskell, donc j'ai du mal à déchiffrer les messages d'erreur suivants:

Prelude> :l Graph.hs
[1 of 1] Compiling Graph            ( Graph.hs, interpreted )

Graph.hs:14:33: error:
• Couldn"t match type ‘a0 -> c0’ with ‘[Char]’
Expected type: Label
Actual type: a0 -> c0
• Probable cause: ‘(.)’ is applied to too few arguments
In the first argument of ‘VariableNode’, namely ‘(fst . fst x)’
In the first argument of ‘(:)’, namely
‘(VariableNode (fst . fst x) (snd . fst x) (snd x))’
In the expression:
(VariableNode (fst . fst x) (snd . fst x) (snd x)) : makePGM xs

Graph.hs:14:39: error:
• Couldn"t match expected type ‘a0 -> (c0, b0)’
with actual type ‘(Label, Potential)’
• Possible cause: ‘fst’ is applied to too many arguments
In the second argument of ‘(.)’, namely ‘fst x’
In the first argument of ‘VariableNode’, namely ‘(fst . fst x)’
In the first argument of ‘(:)’, namely
‘(VariableNode (fst . fst x) (snd . fst x) (snd x))’

Graph.hs:14:47: error:
• Couldn"t match type ‘a1 -> c1’ with ‘Float’
Expected type: Potential
Actual type: a1 -> c1
• Probable cause: ‘(.)’ is applied to too few arguments
In the second argument of ‘VariableNode’, namely ‘(snd . fst x)’
In the first argument of ‘(:)’, namely
‘(VariableNode (fst . fst x) (snd . fst x) (snd x))’
In the expression:
(VariableNode (fst . fst x) (snd . fst x) (snd x)) : makePGM xs

Graph.hs:14:53: error:
• Couldn"t match expected type ‘a1 -> (a2, c1)’
with actual type ‘(Label, Potential)’
• Possible cause: ‘fst’ is applied to too many arguments
In the second argument of ‘(.)’, namely ‘fst x’
In the second argument of ‘VariableNode’, namely ‘(snd . fst x)’
In the first argument of ‘(:)’, namely
‘(VariableNode (fst . fst x) (snd . fst x) (snd x))’
Failed, modules loaded: none.

J'ai conclu qu'il existe des incompatibilités de types, mais je ne sais pas comment, étant donné les types que j'ai définis et les fonctions de type signature.

Réponses:

2 pour la réponse № 1

Le problème est que f . g x est f . (g x). Par conséquent, les types ne correspondent pas:

fst . fst ((1,2),3)
== fst . (fst ((1,2),3))
== fst . (1,2)
== ???? (.) expects a function, not a value

Vous devez soit utiliser les parenthèses autour de fst . fst ou $:

-- reminder:
(.) :: (b -> c) -> (a -> b) -> a -> c
(.) f g x = f (g x)

($) :: (a -> b) -> a -> b
($) f x = f x

(fst . fst) x
== fst (fst  x)

fst $ fst x
== fst (fst x)

Vous pouvez également combiner les deux, par ex. fst . fst $ x, puisque la préséance de $ est faible.


0 pour la réponse № 2

Bien sûr, c'est un exercice utile à faire età la suite de cette erreur, vous avez appris à mieux comprendre la préséance et l’analyse des opérateurs dans Haskell. Cependant, une fois que vous aurez plus d’expérience, vous réaliserez que vous auriez pu éviter le problème et finir avec du code plus simple. en utilisant la correspondance de motif au lieu de composer des appels à fst et snd:

makePGM :: [((Label, Potential), LabelSet)] -> PGM
makePGM (((label, potential), set):xs) = VariableNode label potential set : makePGM xs
makePGM [] = []

Maintenant, le code a la forme des données qu'il consomme et vous donnez des noms descriptifs aux valeurs avec lesquelles vous travaillez.

Une autre amélioration vient de l'observation queCe motif récursif est très courant: vous faites quelque chose à chaque élément de la liste, indépendamment l'un de l'autre, et vous construisez une liste des résultats. En fait, c'est exactement ce que map Est-ce que. Vous pouvez donc écrire une fonction qui ne traite qu’un seul de ces éléments PGM à la fois, puis utiliser map pour l'étendre à une fonction qui fonctionne sur une liste d'entre eux:

makePGM :: [((Label, Potential), LabelSet)] -> PGM
makePGM = map go
where go ((label, potential), set) = VariableNode label potential set