lomeo: (лямбда)
[personal profile] lomeo
Расширения типа fundep или MPTC обычно понятны бывают сразу, ну, по крайней мере, их идея. А вот чтобы разобраться с ошибками при инстанциировании класса, придётся разобраться.


-XConstrainedClassMethods
Позволяет определять контекст над переменными типа из объявления класса в объявлениях методов.
Частичная задача -XFlexibleContexts.

Пример
{-# LANGUAGE MultiParamTypeClasses, ConstrainedClassMethods #-}

class Map m k v where
    empty :: m k v
    put   :: k -> v -> m k v -> m k v
    get   :: Eq k => k -> m k v -> Maybe v


Здесь в get определён контекст для k.

-XUndecidableInstances
Аналог синонимов типов. Синонимы класса. Применяется совместно с FlexibleInstances.

Пример
{-# LANGUAGE FlexibleInstances, UndecidableInstances #-}

class ObservableEq a where
    (===) :: a -> a -> Bool

instance Eq a => ObservableEq a where
    (===) = (==)


Экземпляр класса здесь представляет не конкретный тип, а (Eq a) => a.

-XOverlappingInstances
С предыдущей опцией можно наворотить кучу инстансов, которые могут быть применимы к одному и тому же набору типов.

{-# LANGUAGE FlexibleInstances, UndecidableInstances, OverlappingInstances #-}

class ObservableEq a where
    (===) :: a -> a -> Bool

instance Eq a => ObservableEq a where
    (===) = (==)

instance ObservableEq [a] where
    (x:xs) === (y:ys) = True
    _      === _      = False


И вот мы применяем (===) к [Int]. Какой инстанс сработает?

При включении флага OverlappingInstances GHC не будет ругаться, а выберет более точный инстанс (в нашем случае последний).

-XIncoherentInstances
Пойдём дальше, предположим, что некой функции мы выбрали наиболее точный инстанс, однако эта функция может примениться к типу, для которого подходит ещё более точный инстанс. Код:

{-# LANGUAGE FlexibleInstances, UndecidableInstances, OverlappingInstances, IncoherentInstances #-}
class ObservableEq a where
    (===) :: a -> a -> Bool

instance Eq a => ObservableEq a where
    (===) = (==)

instance ObservableEq [a] where
    (===) = undefined

instance ObservableEq [Integer] where
    (===) = (==)

tailsObsEq xs ys = tail xs === tail ys


Здесь тип tailsObsEq :: (ObservableEq [a]) => [a] -> [a] -> Bool, т.е. был применён второй instance. Если мы выключим ключик IncoherentInstances, то поимеем ошибку при сравнении tailsObsEq [1] [1], т.к. это уже тип [Integer]. IncoherentInstances же закрепляет за tailsObsEq навсегда второй инстанс.

На сегодня всё :-) Более общие вещи типа FlexibleInstance ещё до тонкостей не понимаю.
This account has disabled anonymous posting.
If you don't have an account you can create one now.
HTML doesn't work in the subject.
More info about formatting

Profile

lomeo: (Default)
Dmitry Antonyuk

April 2024

S M T W T F S
 123456
7891011 1213
14151617181920
21222324252627
282930    

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags
Page generated Jul. 29th, 2025 09:25 am
Powered by Dreamwidth Studios