【问题标题】:Typeclass constraint of different kind不同类型的类型类约束
【发布时间】:2011-10-19 17:30:50
【问题描述】:

我一直在摆弄 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* -> * 类型的类。 我是否可以创建与它所约束的类型类不同类型的类型类约束?

【问题讨论】:

    标签: haskell typeclass type-constraints


    【解决方案1】:

    在任何情况下,您都可以使用多参数类型类来表达底层逻辑(事实上它是在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】:

      当然可以。例如。这对于相同的两个类都可以正常工作:

      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)
      

      你不能做的是在约束中添加新变量。

      【讨论】:

      • 这可能会阻止你做你想做的事。当您谈论一般 l as 时,知道 HasEmpty (l ()) 并没有多大帮助
      • 对,他真正想要的是class (forall a. HasEmpty (l a)) => ...,这是不允许的(而且我认为不能合理添加)。但第二种选择可能更可行。
      • 可能想在其中添加一个fundep l -> a。不确定。
      猜你喜欢
      • 1970-01-01
      • 2017-01-21
      • 2022-10-06
      • 1970-01-01
      • 1970-01-01
      • 2012-09-06
      • 1970-01-01
      • 2014-10-02
      • 1970-01-01
      相关资源
      最近更新 更多