Difference between revisions of "Ru/GHC/Class Instance Extensions"

From HaskellWiki
< Ru
Jump to: navigation, search
 
Line 44: Line 44:
 
<haskell>
 
<haskell>
 
{-# LANGUAGE FlexibleInstances, UndecidableInstances, OverlappingInstances #-}
 
{-# LANGUAGE FlexibleInstances, UndecidableInstances, OverlappingInstances #-}
class Eq a => ObservableEq a where
+
 
 +
class ObservableEq a where
 +
    (===) :: a -> a -> Bool
 +
 
 +
instance Eq a => ObservableEq a where
 
     (===) = (==)
 
     (===) = (==)
  
class ObservableEq [a] where
+
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 навсегда второй инстанс.