/ Chyba prirovnávania typu Haskell - haskell

Haskellová zhoda typu - haskell

Definovala som niekoľko synonymov typu:

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

Navyše som definoval nasledujúci typ a typ synonym:

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

Nakoniec nasledujúca funkcia na vytvorenie grafu:

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

Vo vyššie uvedenej funkcii je uvedený zoznam n-tíc, kde prvým prvkom n-tice je ďalšia n-tka a druhá je zoznam podľa podpisu typu funkcie.

Som nový pre Haskell, takže mám nejaké ťažkosti s dešifrovaním nasledujúcich chybových hlásení:

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.

Dospela som k záveru, že existujú nezhody medzi typmi, ale nie je jasné, ako to, vzhľadom na typy, ktoré som definoval, a podpis typov funkcií.

odpovede:

2 pre odpoveď č. 1

Problém je, že f . g x je f . (g x), Preto sa typy nedajú zhodovať:

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

Musíte buď použiť zátvorky fst . fst alebo $:

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

Môžete tiež kombinovať obe, napr. fst . fst $ x, pretože prednosť $ je nízky.


0 pre odpoveď č. 2

Samozrejme, je to užitočné cvičenie, ktoré treba urobiť, aako výsledok tejto chyby, ste sa naučili lepšie porozumieť prednosti a analýze operátorov v Haskell, ale akonáhle budete mať viac skúseností, uvedomíte si, že ste sa mohli vyhnúť problému a následne zlikvidovať jednoduchším kódom ako výsledok pomocou prispôsobenia vzoru namiesto toho, aby ste vytvorili volania fst a snd:

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

Teraz je kód tvarovaný ako dáta, ktoré spotrebuje, a dostanete opisné názvy hodnôt, s ktorými pracujete.

Ďalšie zlepšenie vychádza z toho, že to pozorujemetento rekurzívny vzor je veľmi bežný: urobíte niečo pre každú položku v zozname nezávisle od seba a zostavíte zoznam výsledkov. V skutočnosti to je presne to, čo map robí. Takže môžete napísať funkciu, ktorá sa zaoberá iba jednou z týchto položiek PGM naraz a potom ju používať map rozšíriť ho na funkciu, ktorá funguje na zozname:

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