Ограничение класса типов различного вида - PullRequest
4 голосов
/ 19 октября 2011

Я возился с общими классами типов для списков в Haskell.

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 является классом для типов вида * -> *. Могу ли я сделать ограничение класса типов другого типа, чем класс типов, который он ограничивает?

Ответы [ 2 ]

3 голосов
/ 19 октября 2011

В любом случае вы всегда можете выразить основную логику, используя многопараметрические классы типов (как на самом деле это делается в ListLike ):

{-# 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)
2 голосов
/ 19 октября 2011

Конечно можно.Например, это будет хорошо работать для тех же двух классов:

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)

Что вы не можете сделать, это добавить новые переменные в ограничениях.

...