Ограничение Typeclass разного рода
-
26-10-2019 - |
Вопрос
Я возился с общими классами типов для списков в Хаскелле.
class HasEmpty a where
empty :: a
isEmpty :: a -> Bool
class HasEmpty (l a) => List l where
cons :: a -> l a -> l a
uncons :: l a -> (a, l a)
Чтобы дать вам представление о том, как это может работать, вот случаи для []
:
instance HasEmpty [a] where
empty = []
isEmpty [] = True
isEmpty _ = False
instance List [] where
cons = (:)
uncons (x:xs) = (x,xs)
Однако это вызывает ошибку:
Not in scope: type variable 'a'
Это вызвано ограничением HasEmpty (l a)
. Анкет Меня не отчаянно заинтересованы в этом конкретном примере, но меня заинтересован в концепции в целом. HasEmpty
это класс для видов *
, пока List
это класс для видов * -> *
. Возможно ли я сделать ограничение типового класса другого вида, чем тип, он ограничивает?
Решение
В любом случае вы всегда можете выразить базовую логику либо с использованием многопараметрических типов (как на самом деле это делается в Список):
{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances #-}
class HasEmpty a where
empty :: a
isEmpty :: a -> Bool
class HasEmpty (l a) => List l a where
cons :: a -> l a -> l a
uncons :: l a -> (a, l a)
instance HasEmpty [a] where
empty = []
isEmpty [] = True
isEmpty _ = False
instance List [] a where
cons = (:)
uncons (x:xs) = (x,xs)
Или более элегантно через семьи типа:
{-# LANGUAGE TypeFamilies #-}
class HasEmpty a where
empty :: a
isEmpty :: a -> Bool
class HasEmpty a => List a where
type Elem a :: *
cons :: Elem a -> a -> a
uncons :: a -> (Elem a, a)
instance HasEmpty [a] where
empty = []
isEmpty [] = True
isEmpty _ = False
instance List [a] where
type Elem [a] = a
cons = (:)
uncons (x:xs) = (x,xs)
Другие советы
Конечно вы можете. Например, это будет работать нормально для тех же двух классов:
class HasEmpty (l ()) => List l where
cons :: a -> l a -> l a
uncons :: l a -> (a, l a)
или где List1 :: (* -> *) -> * -> *
)
class HasEmpty1 (l a) => List1 l a where
cons :: a -> l a -> l a
uncons :: l a -> (a, l a)
Что вы не можете сделать, так это добавить новые переменные в ограничениях.