/ / Błąd dopasowania typu Haskella - haskell

Błąd dopasowania typu Haskella - haskell

Zdefiniowałem kilka rodzajów synonimów w następujący sposób:

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

Ponadto zdefiniowałem następujący typ i typ synonimu:

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

Na koniec poniższa funkcja do utworzenia wykresu:

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

W powyższej funkcji znajduje się lista krotek, gdzie pierwszym elementem krotki jest kolejna krotka, a druga lista, zgodnie z podpisem typu funkcji.

Jestem nowy w Haskell, więc mam problemy z odczytaniem następujących komunikatów o błędach:

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.

Doszedłem do wniosku, że są niedopasowania typu, ale nie jestem jasne, jak to zrobić, biorąc pod uwagę typy, które zdefiniowałem i funkcje typu podpisu.

Odpowiedzi:

2 dla odpowiedzi № 1

Problemem jest f . g x jest f . (g x). Dlatego typy nie pasują:

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

Musisz użyć nawiasów wokół fst . fst lub $:

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

Możesz także połączyć oba, np. fst . fst $ x, ponieważ pierwszeństwo ma $ jest niski.


0 dla odpowiedzi nr 2

Oczywiście jest to przydatne ćwiczenie, iw wyniku popełnienia tego błędu nauczyłeś się lepiej rozumieć pierwszeństwo operatora i parsowanie w Haskell, ale gdy zdobędziesz więcej doświadczenia, uświadomisz sobie, że mógłbyś uniknąć problemu i wyeliminować go prostszym kodem, przy użyciu dopasowywania wzorców zamiast komponowania wywołań fst i snd:

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

Teraz kod ma kształt danych, które zużywa, i dajesz opisowe nazwy wartości, z którymi pracujesz.

Kolejna poprawa wynika z obserwacji tegoten wzór rekurencyjny jest bardzo powszechny: robisz coś dla każdej pozycji na liście, niezależnie od siebie i konstruujesz listę wyników. W rzeczywistości to jest dokładnie to, co map robi. Możesz więc napisać funkcję, która zajmuje się tylko jednym z tych elementów PGM naraz, a następnie użyj map rozszerzyć go do funkcji, która działa na liście z nich:

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