简体   繁体   English

不同种类的类型约束

[英]Typeclass constraint of different kind

I have been fiddling with general type classes for lists in Haskell. 我一直在摆弄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)

To give you an idea of how it might work, here are instances for [] : 为了让您了解它是如何工作的,这里是[]实例:

instance HasEmpty [a] where
  empty = []
  isEmpty [] = True
  isEmpty _  = False

instance List [] where
  cons = (:)
  uncons (x:xs) = (x,xs)

However, this raises an error: 但是,这会引发错误:

Not in scope: type variable 'a'

This is caused by the constraint HasEmpty (la) . 这是由约束HasEmpty (la)引起的。 I am not desperately interested in this particular example, but I am interested in the concept in general. 我并不是对这个特殊的例子非常感兴趣,但我对这个概念感兴趣。 HasEmpty is a class for types of kind * , while List is a class for types of kind * -> * . HasEmpty是类型*的类,而List是类型* -> * Is it possible for me to make a typeclass constraint of a different kind than the typeclass it is constraining? 我是否有可能创建一个与它所约束的类型类不同的类型类约束?

In any case you can always express underlying logic either using multiparameter typeclasses (as in fact it is done in ListLike ): 在任何情况下,您总是可以使用多参数类型类来表达底层逻辑(实际上它是在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)

Or more elegantly via type families: 或者通过类型系列更优雅:

{-# 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)

Of course you can. 当然可以。 Eg this will work fine for the same two classes: 例如,这将适用于相同的两个类:

class HasEmpty (l ()) => List l where
  cons :: a -> l a -> l a
  uncons :: l a -> (a, l a)

or (where List1 :: (* -> *) -> * -> * ) 或(其中List1 :: (* -> *) -> * -> *

class HasEmpty1 (l a) => List1 l a where
  cons :: a -> l a -> l a
  uncons :: l a -> (a, l a)

What you can't do is add new variables in constraints. 你不能做的是在约束中添加新变量。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM