Haskell 当类型类只有一个参数时,具有两个参数的类型的类型类实例

Haskell 当类型类只有一个参数时,具有两个参数的类型的类型类实例,haskell,typeclass,Haskell,Typeclass,考虑以下类型类: class Listable a where asList :: a t -> [t] 使用一个参数为类型创建实例非常简单: instance Listable [] where asList = id instance Listable Maybe where asList (Just x) = [x] asList Nothing = [] class Listable t where type ListableElem t ::

考虑以下类型类:

class Listable a where
   asList :: a t -> [t]
使用一个参数为类型创建实例非常简单:

instance Listable [] where
   asList = id

instance Listable Maybe where
   asList (Just x) = [x]
   asList Nothing = []
class Listable t where
    type ListableElem t :: *
    asList :: t -> [ListableElem t]
现在,我如何为具有两个相同类型参数的pair创建一个实例?当然,我可以做一些包装:

data V2 a = V2 a a

v2 (p,q) = V2 p q

instance Listable V2 where
   asList (V2 p q) = [p,q]
现在我可以编写类似于
asList$v2(47,11)
的东西,但这种方法无法达到目的


有没有办法将pair的类型限制在两个类型参数相等的情况下,并为此编写一个
Listable
实例?如果没有,通常的解决方法是什么?

您必须定义一些包装器类型才能做到这一点。(但是,您应该使用newtype。)您甚至可以定义:

newtype Foo t a = Foo(t a a)

instance Listable (Foo (,)) where
   asList (Foo (a,b)) = [a,b]

从概念上讲,有很多方法可以做到这一点。不幸的是,它们中的大多数实际上并不起作用。唉

首先,作为一名函数式程序员,我敢打赌这是您真正想写的:

instance Listable (\a -> (a, a)) where
    asList (p, q) = [p,q]
不幸的是,类型级别的lambda不存在。我们可以使用类型同义词编写上述lambda的命名版本:

type Same2 f a = f a a

instance Listable (Same2 (,)) where { ... }
这也是不允许的,因为类型同义词没有完全应用。相反,我们可以想象type类使用一个额外的参数来描述如何应用类型变量:

class Listable app f where
    asList :: app f a -> [a]

instance Listable __ Maybe where { ... }

instance Listable __ (,) where { ... }
甚至不考虑
app
可能是什么,这也会失败,因为
f
参数的类型不一致

继续讨论实际可行的方法,我认为最常见的方法是将类型同义词方法包装在
newtype
中,然后处理涉及的包装和展开

newtype Same2 f a = Same2 (f a a)

instance Listable (Same2 (,)) where { ... }
这是可行的,虽然有点难看。你也可以用这种方式定义类型构造器组合和其他玩具,然后在一堆跳圈样板下使用类型级别点自由表达式

作为最后一种方法,您还可以将上面的lambda样式方法编码为“反向”,从完全应用的版本编码为单个类型参数:

instance Listable [] where
   asList = id

instance Listable Maybe where
   asList (Just x) = [x]
   asList Nothing = []
class Listable t where
    type ListableElem t :: *
    asList :: t -> [ListableElem t]

能够做这类事情是类型族的主要动机之一。MPTCs和fundeps也可以表达同样的东西,但它1)等效,2)更难看,所以我不会费心写出来。

很抱歉懒得尝试,但最后一种方法将允许
实例可列表(a,a)
-不是吗?@yatima2975:以牺牲
(,)的不同实例为代价
作为最外层的类型构造函数,是的。也许我应该在我的回答中举个例子,既然你提到了。。。