/ / Помилка узгодження типу типу 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