Вопрос

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

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)

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top