/ Erro de correspondência do tipo Haskell - haskell

Erro de correspondência do tipo Haskell - haskell

Eu defini alguns tipos de sinônimos da seguinte forma:

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

Além disso, defini o seguinte tipo e tipo de sinônimo:

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

Finalmente, a seguinte função para construir um gráfico:

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

Na função acima, uma lista de tuplas é fornecida onde o primeiro elemento da tupla é outra tupla e a segunda uma lista, conforme a assinatura do tipo de funções.

Eu sou novo no Haskell então estou tendo alguma dificuldade em decifrar as seguintes mensagens de erro:

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.

Eu concluí que há incompatibilidades de tipos, mas não estou claro como, dado os tipos que defini e as funções tipo assinatura.

Respostas:

2 para resposta № 1

O problema é que f . g x é f . (g x). Portanto, os tipos não correspondem:

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

Você tem que usar parênteses ao redor fst . fst ou $:

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

Você também pode combinar os dois, por exemplo fst . fst $ x, desde a precedência de $ é baixo.


0 para resposta № 2

Claro, este é um exercício útil para fazer, eComo resultado de cometer esse erro, você aprendeu a entender melhor a precedência e a análise do operador em Haskell. No entanto, uma vez que você tenha mais experiência, perceberá que poderia ter evitado o problema e acabou resultando em um código mais simples. usando correspondência de padrões em vez de compor chamadas para fst e snd:

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

Agora, o código tem o formato dos dados que ele consome e você pode fornecer nomes descritivos aos valores com os quais trabalha.

Outra melhoria vem da observação de queEsse padrão recursivo é muito comum: você faz algo para cada item da lista, independente um do outro, e constrói uma lista dos resultados. Na verdade, isso é exatamente o que map faz. Então você poderia escrever uma função que lida com apenas um desses itens PGM por vez, e então usar map para estendê-lo a uma função que funciona em uma lista deles:

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