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

From HaskellWiki
< Ru
Jump to: navigation, search
 
m
 
(3 intermediate revisions by 2 users not shown)
Line 1: Line 1:
[[Category:RU|GHC|Extensions]]
 
 
 
==-XConstrainedClassMethods==
 
==-XConstrainedClassMethods==
  
Line 44: Line 42:
 
<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>
  
Line 78: Line 81:
  
 
Здесь тип tailsObsEq :: (ObservableEq [a]) => [a] -> [a] -> Bool, т.е. был применён второй instance. Если мы выключим ключик IncoherentInstances, то поимеем ошибку при сравнении tailsObsEq [1] [1], т.к. это уже тип [Integer]. IncoherentInstances же закрепляет за tailsObsEq навсегда второй инстанс.
 
Здесь тип tailsObsEq :: (ObservableEq [a]) => [a] -> [a] -> Bool, т.е. был применён второй instance. Если мы выключим ключик IncoherentInstances, то поимеем ошибку при сравнении tailsObsEq [1] [1], т.к. это уже тип [Integer]. IncoherentInstances же закрепляет за tailsObsEq навсегда второй инстанс.
 +
 +
[[Category:Ru]]
 +
[[Category:GHC]]
 +
[[Category:Language extensions‏‎]]

Latest revision as of 23:05, 29 June 2021

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