Гм... если что — прошу смеяться громко, чтобы проняло.
Имеем следующий код:
module Maps
where
data MapNode key value =
Null
| Leaf key value
| Node (MapNode key value) key value (MapNode key value)
deriving Show
class Map m where
insert :: m -> k -> v -> m
erase :: m -> k -> m
data GovnoMap key value = GovnoMap { root :: MapNode key value }
deriving Show
instance Map (GovnoMap key value)
where
-- insert
insert m@(GovnoMap Null) k v = m{root=Leaf k v} -- Maps.hs:20
из которого прекрасно видно, что я изучаю язык haskell.
На это безобразие компилер (The Glorious Glasgow Haskell Compilation System, version 6.4.2) я так подозреваю законно ругается
Prelude> :r
Compiling Maps ( Maps.hs, interpreted )
Maps.hs:20:52:
Couldn't match the rigid variable `key' against the rigid variable `k'
`key' is bound by the instance declaration at Maps.hs:17:0
`k' is bound by the type signature for `insert'
Expected type: key
Inferred type: k
In the first argument of `Leaf', namely `k'
In the `root' field of a record
Failed, modules loaded: none.
Я так догадался, что он хочет на этапе компиляции (без даже примеров использования ф-ий) быть уверенным, что тип key из instance равен типу k из instance::insert, но это противоречит правилам вывода типов для обычных функций.
Требуется подсказка — как это исправить и почему в данном случае компилятор накладывает такие жесткие ограничения
Здравствуйте, Garrrrr, Вы писали:
G>Я так догадался, что он хочет на этапе компиляции (без даже примеров использования ф-ий) быть уверенным, что тип key из instance равен типу k из instance::insert, но это противоречит правилам вывода типов для обычных функций.
Да.
G>Требуется подсказка — как это исправить и почему в данном случае компилятор накладывает такие жесткие ограничения
Ограничения не жесткие — это же язык со статической типизацией.
Исправить можно, явно привязав k и v к Map:
class Map m where
insert :: m k v -> k -> v -> m k v
erase :: m k v -> k -> m k v
instance Map GovnoMap
where
...
Вот так компилируется:
class Map m where
insert :: m k v -> k -> v -> m k v
erase :: m k v -> k -> m k v
data GovnoMap key value = GovnoMap { root :: MapNode key value }
deriving Show
instance Map GovnoMap
where
insert m@(GovnoMap Null) k v = GovnoMap {root=Leaf k v}
Posted via RSDN NNTP Server 2.0
Здравствуйте, Garrrrr, Вы писали:
G>Гм... если что — прошу смеяться громко, чтобы проняло.
Уговорил.
G>На это безобразие компилер (The Glorious Glasgow Haskell Compilation System, version 6.4.2) я так подозреваю законно ругается
Правильно подозреваешь.
G>Я так догадался, что он хочет на этапе компиляции (без даже примеров использования ф-ий) быть уверенным, что тип key из instance равен типу k из instance::insert, но это противоречит правилам вывода типов для обычных функций.
Не очень понял твою мысль, но на правду похоже.
G>Требуется подсказка — как это исправить и почему в данном случае компилятор накладывает такие жесткие ограничения
Вариант раз: определить класс для "обёртки" GovnoMap — в предполжении, что любой инстанс Map может хранить значения и ключи произвольного типа:
module Maps where
data MapNode key value = Null |
Leaf key value |
Node (MapNode key value) key value (MapNode key value)
deriving Show
class Map m where
insert :: m k v -> k -> v -> m k v
erase :: m k v -> k -> m k v
data GovnoMap key value = GovnoMap { root :: MapNode key value } deriving Show
instance Map GovnoMap where
insert m@(GovnoMap Null) k v = m{root=Leaf k v}
Вариант два: ввести в определение класса типы ключей и значений, в предположении, что инстанс всегда будет некоей "обёрткой", то есть будет иметь вид "Что-то-там key value".
{-# OPTIONS_GHC -fglasgow-exts #-}
-- нужно, поскольку классы с несколькими параметрами - расширение GHC.
module Maps where
data MapNode key value = Null |
Leaf key value |
Node (MapNode key value) key value (MapNode key value)
deriving Show
class Map m k v where
insert :: m k v -> k -> v -> m k v
erase :: m k v -> k -> m k v
data GovnoMap key value = GovnoMap { root :: MapNode key value } deriving Show
instance Map GovnoMap key value where
insert m@(GovnoMap Null) k v = m{root=Leaf k v}
Вариант три: использовать фундепсы (тоже расширение GHC). Это — самый прямой вариант.
{-# OPTIONS_GHC -fglasgow-exts #-}
module Maps where
data MapNode key value = Null |
Leaf key value |
Node (MapNode key value) key value (MapNode key value)
deriving Show
class Map m k v | m -> k, m -> v where
insert :: m -> k -> v -> m
erase :: m -> k -> m
data GovnoMap key value = GovnoMap { root :: MapNode key value } deriving Show
instance Map (GovnoMap key value) key value where
insert m@(GovnoMap Null) k v = m{root=Leaf k v}
Вообще, ты столкнулся с типичной проблемой коллекций в хаскеле. Без расширений она по нормальному не решается.