/ / Haskell type passender Fehler - haskell

Haskell type passender Fehler - haskell

Ich habe ein paar Synonymen wie folgt definiert:

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

Zusätzlich habe ich folgenden Typ und Typ definiert:

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

Schließlich die folgende Funktion, um ein Diagramm zu konstruieren:

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

In der obigen Funktion ist eine Liste von Tupeln vorgesehen, wobei das erste Element des Tupels ein anderes Tupel und das zweite eine Liste gemäß der Signatur des Funktionstyps ist.

Ich bin neu in Haskell, habe also einige Schwierigkeiten bei der Entschlüsselung der folgenden Fehlermeldungen:

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.

Ich bin zu dem Schluss gekommen, dass es Typinkongruenzen gibt, aber ich bin mir nicht sicher, wie das der Fall ist, wenn man die Typen, die ich definiert habe, und die Funktionen Signatur angibt.

Antworten:

2 für die Antwort № 1

Das Problem ist, dass f . g x ist f . (g x). Daher stimmen die Typen nicht überein:

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

Sie müssen entweder runde Klammern verwenden fst . fst oder $:

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

Sie können auch beide kombinieren, z.B. fst . fst $ xseit dem Vorrang von $ ist niedrig.


0 für die Antwort № 2

Natürlich ist dies eine nützliche Übung zu tun, undAls Ergebnis dieses Fehlers haben Sie gelernt, Operator Vorrang und Parsing in Haskell besser zu verstehen. Sobald Sie jedoch mehr Erfahrung haben, werden Sie erkennen, dass Sie das Problem vermieden haben könnten, und als Ergebnis mit einfacheren Code endete Verwenden des Mustervergleichs anstelle des Verfassens von Aufrufen fst und snd:

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

Jetzt ist der Code wie die Daten geformt, die er verbraucht, und Sie erhalten beschreibende Namen für die Werte, mit denen Sie arbeiten.

Eine weitere Verbesserung ergibt sich aus der BeobachtungDieses rekursive Muster ist sehr gebräuchlich: Sie machen unabhängig von einander etwas für jedes Element in der Liste und erstellen eine Liste der Ergebnisse. Genau das ist es tatsächlich map tut. Sie können also eine Funktion schreiben, die jeweils nur eines dieser PGM-Elemente behandelt und dann verwendet map um es auf eine Funktion zu erweitern, die auf einer Liste von ihnen funktioniert:

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