我有以下使用 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 的一些候选版本(不是官方版本!)一起使用。恕我直言,它不应该工作,但是,有两个原因:
- for 的类型声明在上下文中
prefixApp
缺少一个(用于正确类型检查。VNum m
prepend (f b)
- 更有问题:ghc 7.4.2 不假设 TypeOperator
:+
在其第一个参数中是单射的(也不是第二个,但这里不是必需的),这会导致类型错误:从类型声明中,我们知道vec
必须有type并且类型检查器为定义右侧Vec (n:+k) a
的表达式推断出. 但是:类型检查器无法推断出这一点(因为没有单射的保证)。split vec
Vec (n:+k0) a
k ~ k0
:+
有谁知道第二个问题的解决方案?我怎样才能在它的第一个论点中声明:+
是单射的和/或我怎样才能完全避免遇到这个问题?