Difference between revisions of "Ru/GHC/Class Instance Extensions"
Line 44: | Line 44: | ||
<haskell> |
<haskell> |
||
{-# LANGUAGE FlexibleInstances, UndecidableInstances, OverlappingInstances #-} |
{-# LANGUAGE FlexibleInstances, UndecidableInstances, OverlappingInstances #-} |
||
+ | |||
⚫ | |||
+ | class ObservableEq a where |
||
+ | (===) :: a -> a -> Bool |
||
+ | |||
⚫ | |||
(===) = (==) |
(===) = (==) |
||
− | + | instance ObservableEq [a] where |
|
(x:xs) === (y:ys) = True |
(x:xs) === (y:ys) = True |
||
_ === _ = False |
_ === _ = False |
||
+ | |||
</haskell> |
</haskell> |
||
Revision as of 09:30, 30 July 2008
-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 навсегда второй инстанс.