/ / Грешка за съвпадение на тип Haskell - haskell

Грешка при съвпадение на тип Haskell - haskell

Имам дефинирани няколко типа синоними, както следва:

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

Освен това съм определил следния тип и тип синоним:

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

И накрая, следващата функция за конструиране на графика:

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

В горната функция е предвиден списък с типове, където първият елемент на плика е друга тона, а втората - списък, според подписа на типа функции.

Аз съм нов за Haskell, така че имам някои трудности при дешифриране на следните съобщения за грешка:

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.

Аз заключих, че има типове несъответствия, но не съм ясен как така, като се има предвид типовете, които съм определил и типовете функции подпис.

Отговори:

2 за отговор № 1

Проблемът е, че f . g x е f . (g x), Следователно типовете не съвпадат:

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

Или трябва да използвате скоби наоколо fst . fst или $:

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

Можете също така да комбинирате и двете, напр. fst . fst $ x, тъй като предимството на $ е ниско.


0 за отговор № 2

Разбира се, това е полезно упражнение ив резултат на тази грешка сте се научили да разбирате по-добре оператора с предимство и анализ в Haskell, но след като сте имали повече опит, ще осъзнаете, че сте успели да избегнете проблема и сте се събрали с по-прост код като резултат от като се използва съвпадение на шаблона, вместо да се съставят обаждания fst и snd:

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

Сега кодът е оформен като данните, които консумира, и можете да дадете описателни имена на стойностите, с които работите.

Друго подобрение идва от товатози рекурсивен модел е много чести: правите нещо за всеки елемент в списъка, независимо един от друг и създавате списък с резултатите. Всъщност това е точно така map прави. Така че можете да напишете функция, която се занимава само с един от тези PGM елементи в даден момент, а след това да ги използвате map да го разширите до функция, която работи върху списък от тях:

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