Personal tools

Ru/GHC/Class Instance Extensions

From HaskellWiki

< Ru
Jump to: navigation, search

Contents

1 -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.

2 -XUndecidableInstances

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

Пример

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


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

3 -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 не будет ругаться, а выберет более точный инстанс (в нашем случае последний).

4 -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 навсегда второй инстанс.