/ / Errore di corrispondenza del tipo Haskell - haskell

Errore di corrispondenza del tipo Haskell - haskell

Ho definito un paio di sinonimi tipo come segue:

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

Inoltre ho definito il seguente sinonimo di tipo e tipo:

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

Infine, la seguente funzione per costruire un grafico:

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

Nella funzione precedente, viene fornita una lista di tuple dove il primo elemento della tupla è un'altra tupla e il secondo un elenco, come per la firma del tipo di funzioni.

Sono nuovo di Haskell quindi sto avendo qualche difficoltà a decifrare i seguenti messaggi di errore:

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.

Ho concluso che ci sono discrepanze di tipo ma non sono chiaro in che modo, dati i tipi che ho definito e le funzioni di tipo firma.

risposte:

2 per risposta № 1

Il problema è che f . g x è f . (g x). Pertanto, i tipi non corrispondono:

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

O devi usare parentesi in giro fst . fst o $:

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

Puoi anche combinare entrambi, ad es. fst . fst $ x, poiché la precedenza di $ è basso.


0 per risposta № 2

Naturalmente, questo è un esercizio utile da fare, ecome risultato di questo errore, hai imparato a capire meglio la precedenza e l'analisi degli operatori in Haskell, tuttavia, una volta che avrai più esperienza, ti renderai conto che avresti potuto evitare il problema e finire con un codice più semplice come risultato, utilizzando la corrispondenza del modello invece di comporre le chiamate a fst e snd:

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

Ora il codice ha la forma dei dati che consuma e puoi dare nomi descrittivi ai valori con cui lavori.

Un altro miglioramento viene dall'osservarloquesto schema ricorsivo è molto comune: fai qualcosa per ogni elemento della lista, indipendente l'uno dall'altro, e costruisci una lista dei risultati. In effetti, questo è esattamente ciò che map lo fa. Quindi potresti scrivere una funzione che si occupa solo di uno di questi elementi PGM alla volta, e poi usarla map per estenderlo a una funzione che funziona su un elenco di loro:

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