从一系列较小的类推出一般的类型类实例?

这个标题确实不是很具描述性,但我不知道如何用简短的标题来描述这个。 我会很感激任何建议!

我将介绍我的问题的一个非常简化的版本:)

所以我有一个typeclass

class Known f a where
    known :: f a

这应该能够在特定的索引处生成给定类型的规范构造,对于使用GADT和其他东西非常有用。 我给出了这个简化版本,以及相关的部分。

所以显然有一个Proxy实例:

instance Known Proxy a where
    known = Proxy

我们可以使用的是:

> known :: Proxy Monad
Proxy

但是这种HList类型也有一个例子:

data Prod f :: [k] -> * where
    PNil :: Prod f '[]
    (:<) :: f a -> Prod f as -> Prod f (a ': as)

infixr 5 (:<)

Prod f '[a,b,c]大致等同于(fa, fb, fc)元组。 相同的函子,不同的类型。

编写实例非常简单:

instance Known (Prod f) '[] where
    known = PNil
instance (Known f a, Known (Prod f) as) => Known (Prod f) (a ': as) where
    known = known :< known

哪个效果不错:(假设一个Show实例)

> known :: Prod Proxy '[1,2,3]
Proxy :< Proxy :< Proxy :< PNil

但是,我在哪里,我需要做的全部“多态”功能的情况下, as ......但GHC不喜欢它。

asProds :: forall as. Proxy as -> Prod Proxy as
asProds _ = known :: Prod Proxy as

它出现了这个错误:

No instance for (Known (Prod f) as)
  arising from a use of 'known'

我的猜测是说,GHC无法显示,将有一个实例,将挑选适用于任何工作as ,或者,它不会有一个战略,构建known该实例。

作为一个人,我知道情况是这样,但是有什么办法可以让这个工作起作用吗? 这些实例都在“范围内”并且可用......但我怎么能告诉GHC如何以满意的方式构建它?


如果对类没有限制,则不能使用它的方法。 只需添加约束:

asProds :: forall as. Known (Prod Proxy) as => Proxy as -> Prod Proxy as
asProds _ = known :: Prod Proxy as  

请注意,GHC可以推断出这种类型:

asProds (_ :: Proxy as) = known :: Prod Proxy as
-- inferred constraint

由于类型被擦除,没有字典的情况下,没有什么可以构建运行时实例。 在所有的居民中都存在这样的情况,但对于我们需要字典的程序 - 建设性证明 - 来说,这在逻辑上是正确的。

写出约束不应该让我们受到太大的影响,因为如果我们有所有情况的实例,那么当我们需要一个实例时,我们通常可以得到一个,并且不常出现异常。 当我们想要一个具有类型系列应用程序的开放类型的实例时例外。 在这种情况下,我们必须编写函数,从其他已知实例中以所需类型显式构建实例。

链接地址: http://www.djcxy.com/p/43539.html

上一篇: Inferring general typeclass instance from a series of smaller ones?

下一篇: Polymorphic function over types combined by typeclass