【发布时间】:2012-08-26 14:38:36
【问题描述】:
我有以下使用 ghcs 扩展 GADTs、TypeOperators 和 DataKinds 的固定长度向量定义:
data Vec n a where
T :: Vec VZero a
(:.) :: a -> Vec n a -> Vec (VSucc n) a
infixr 3 :.
data VNat = VZero | VSucc VNat -- ... promoting Kind VNat
type T1 = VSucc VZero
type T2 = VSucc T1
以及TypeOperator:+的以下定义:
type family (n::VNat) :+ (m::VNat) :: VNat
type instance VZero :+ n = n
type instance VSucc n :+ m = VSucc (n :+ m)
为了使我的整个意图库有意义,我需要将(Vec n b)->(Vec m b) 类型的固定长度向量函数应用于更长向量Vec (n:+k) b 的初始部分。让我们将该函数称为prefixApp。它应该有类型
prefixApp :: ((Vec n b)->(Vec m b)) -> (Vec (n:+k) b) -> (Vec (m:+k) b)
这是一个示例应用程序,其固定长度矢量函数change2 定义如下:
change2 :: Vec T2 a -> Vec T2 a
change2 (x :. y :. T) = (y :. x :. T)
prefixApp 应该能够将change2 应用于长度>=2 的任何向量的前缀,例如
Vector> prefixApp change2 (1 :. 2 :. 3 :. 4:. T)
(2 :. 1 :. 3 :. 4 :. T)
有人知道如何实现prefixApp吗?
(问题是,必须使用固定长度向量函数的一部分类型来获取正确大小的前缀......)
编辑: Daniel Wagners(非常聪明!)解决方案似乎与 ghc 7.6 的某些候选版本(不是官方版本!)一起使用。恕我直言,它不应该工作,但是,有两个原因:
-
prefixApp的类型声明在上下文中缺少VNum m(以便prepend (f b)正确进行类型检查。 - 更有问题:ghc 7.4.2 不假定 TypeOperator
:+在其第一个参数(也不是第二个,但这里不是必需的)中是单射的,这会导致类型错误:来自类型声明,我们知道vec必须具有Vec (n:+k) a类型,并且类型检查器推断定义右侧的表达式split vec类型为Vec (n:+k0) a。但是:类型检查器无法推断出k ~ k0(因为无法保证:+是单射的)。
有人知道第二个问题的解决方案吗?如何在其第一个参数中声明 :+ 是单射的和/或如何完全避免遇到这个问题?
【问题讨论】:
-
看起来这应该可以通过类型类和功能依赖来实现。不幸的是,我的原型代码似乎在 GHC 中出现了一个错误,所以我无法对其进行测试。
-
@gereeter:是的,我同意(理论上!)函数依赖应该是可能的,这实际上是我的第一个方法。不幸的是,由于我不清楚的原因,它没有起作用。不过,我会对使用函数依赖的解决方案感兴趣......
标签: haskell ghc type-systems dependent-type type-level-computation