/ / Error de coincidencia tipo Haskell - haskell

Error de coincidencia tipo Haskell - haskell

He definido un par de sinónimos tipo de la siguiente manera:

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

Además, he definido el siguiente tipo y tipo de sinónimo:

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

Finalmente, la siguiente función para construir un gráfico:

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

En la función anterior, se proporciona una lista de tuplas donde el primer elemento de la tupla es otra tupla y la segunda una lista, según la firma de tipo de funciones.

Soy nuevo en Haskell, así que tengo algunas dificultades para descifrar los siguientes mensajes de error:

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.

He llegado a la conclusión de que hay desajustes de tipos, pero no estoy seguro de qué manera, dado los tipos que he definido y las funciones, escriba la firma.

Respuestas

2 para la respuesta № 1

El problema es ese f . g x es f . (g x). Por lo tanto, los tipos no coinciden:

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

Tienes que usar paréntesis alrededor 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)

También puede combinar ambos, p. fst . fst $ x, ya que la precedencia de $ es bajo.


0 para la respuesta № 2

Por supuesto, este es un ejercicio útil que hacer, yComo resultado de cometer este error, ha aprendido a comprender mejor la precedencia y el análisis del operador en Haskell. Sin embargo, una vez que tenga más experiencia, se dará cuenta de que podría haber evitado el problema y, como resultado, terminar con un código más simple. usando la coincidencia de patrones en lugar de componer llamadas a fst y snd:

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

Ahora el código tiene la forma de los datos que consume, y usted puede dar nombres descriptivos a los valores con los que trabaja.

Otra mejora proviene de observar queeste patrón recursivo es muy común: haces algo con cada elemento de la lista, independientemente el uno del otro, y construyes una lista de los resultados. De hecho, eso es exactamente lo que map hace. Entonces, podría escribir una función que trate solo con uno de estos elementos de PGM a la vez, y luego usar map para extenderlo a una función que funciona en una lista de ellos:

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