[haskell] Непонятки с типами в перегруженных ф-ях
От: Garrrrr  
Дата: 28.09.06 15:57
Оценка:
Гм... если что — прошу смеяться громко, чтобы проняло.
Имеем следующий код:

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, но это противоречит правилам вывода типов для обычных функций.
Требуется подсказка — как это исправить и почему в данном случае компилятор накладывает такие жесткие ограничения
Re: [haskell] Непонятки с типами в перегруженных ф-ях
От: lomeo Россия http://lomeo.livejournal.com/
Дата: 29.09.06 07:59
Оценка:
Здравствуйте, 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
...
Re: [haskell] Непонятки с типами в перегруженных ф-ях
От: Programmierer AG  
Дата: 29.09.06 08:00
Оценка:
Вот так компилируется:
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
Re: [haskell] Непонятки с типами в перегруженных ф-ях
От: Аноним  
Дата: 29.09.06 08:03
Оценка:
Здравствуйте, 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}


Вообще, ты столкнулся с типичной проблемой коллекций в хаскеле. Без расширений она по нормальному не решается.
Re[2]: [haskell] Непонятки с типами в перегруженных ф-ях
От: MigMit Россия http://migmit.vox.com
Дата: 29.09.06 08:05
Оценка: 79 (3)
Здравствуйте, Аноним, Вы писали:

Прошу прощения, только что зарегистрировался, не привык.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.