类型约束中的逻辑含义(Haskell)

时间:2015-01-27 13:32:53

标签: haskell typeclass

我如何表达容器的概念,以实现某些透明属性"?例如,考虑容器类型vShow a暗示Show (v a)

用例是我想要一个函数,其中被调用者决定使用哪个容器,但保证容器在许多类型类约束方面表现良好。

这是我想到的一个(非工作)例子:

mapUnknown :: (forall v. (Functor v, (forall n. Num n => Num (v n)) => v b -> a)) 
              -> [b] -> [a]

这个想法是你传入一个函数,它必须能够处理任何容器类型v。保证vFunctorNum b隐含Num (v b)。如果您传入的b不是Num,则会忽略该规则。

这可能吗?

注意:

以下不起作用:

class Container c a where
  foo :: c a -> [a]

instance forall a c. (Container c a, Show a) => Show (c a) where
  show _ = "whatever"

f :: (Container c a, Show a) => c a -> String
f as =
  show as

这是因为我们可以定义实例Container V aShow (V a)。然后,GHC无法确定是使用show定义的Container还是Show (V a)定义的展示。我们不想定义新的show函数,我们只想在容器的类型已知时断言它存在。

1 个答案:

答案 0 :(得分:1)

好吧,如果我理解正确,你想创建一个类,让我们说NumToNum,这样两个实例NumToNum vNum n编译器就可以推断出那里是Num (v n)的一个实例。以下是如何实现这一目标。

这里的关键是创建一个类型,比如NumI :: * -> *,这样就不会有NumI n类型的任何值,除非n属于类{{1} }}。严格来说,这是不可能的,因为Haskell中的任何类型都有人居住(至少Num)。但是,如果你避免明确地将实现方法标记为(_|_)并深入研究深度递归,那么你就可以相对安全了:

undefined

因此,如果data NumI n where NumI :: Num n => NumI n 不属于n类,则仍然存在Num类型的值undefined,但其他情况并不多。

当然,您需要Num n分机。

现在,可以用这种方式定义上述类:

GADTs

有了这些,您可以通过模式匹配获得class NumToNum v where numToNum :: Num n => NumI (v n) 实例:

Num (v n)

由于构造函数case (numToNum :: NumI (v n)) of NumI => do_something 的类型签名,do_something已经了解Num (v n)实例。

声明NumI类的实例很简单,您只需说明

NumToNum