I have the following definition of fixed-length-vectors using ghcs extensions GADTs
, TypeOperators
and 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
and the following defiition of a TypeOperator :+
:
type family (n::VNat) :+ (m::VNat) :: VNat
type instance VZero :+ n = n
type instance VSucc n :+ m = VSucc (n :+ m)
For my whole intented library to make sense, I need to apply a fixed-length-vector-function of type (Vec n b)->(Vec m b)
to the inial part of a longer vector Vec (n:+k) b
. Let's call that function prefixApp
. It should have type
prefixApp :: ((Vec n b)->(Vec m b)) -> (Vec (n:+k) b) -> (Vec (m:+k) b)
Here's an example application with the fixed-length-vector-function change2
defined like this:
change2 :: Vec T2 a -> Vec T2 a
change2 (x :. y :. T) = (y :. x :. T)
prefixApp
should be able to apply change2
to the prefix of any vector of length >=2, e.g.
Vector> prefixApp change2 (1 :. 2 :. 3 :. 4:. T)
(2 :. 1 :. 3 :. 4 :. T)
Has anyone any idea how to implement prefixApp
?
(The problem is, that a part of the type of the fixed-length-vector-function has to be used to grab the prefix of the right size...)
Edit: Daniel Wagners (very clever!) solution seems to have worked with some release candidate of ghc 7.6 (not an official release!). IMHO it shouldnt work, however, for 2 reasons:
- The type-declaration for
prefixApp
lacks anVNum m
in the context (forprepend (f b)
to typecheck correctly. - Even more problematic: ghc 7.4.2 does not assume the TypeOperator
:+
to be injective in its first argument (nor the second, but thats not essential here), which leads to a type error: from the type-declaration, we know thatvec
must have typeVec (n:+k) a
and the type-checker infers for the expressionsplit vec
on the right-hand side of the definition a type ofVec (n:+k0) a
. But: the type-checker cannot infer thatk ~ k0
(since there is no assurance that:+
is injective).
Does anyone know a solution to this second issue? How can I declare :+
to be injective in its first argument and/or how can I avoid running into this issue at all?