
Wow, thanks, this is almost exactly what I've been looking for. My next trick was going to be to combine "convert", "cons", and "tail" operations.
From your example, we can `cons` an "A" to a Foo to get a BigFoo:
H.cons "A" (Foo 1 2) :: BigFoo BigFoo "A" 1 2
And we can `tail` a BigFoo to get a Foo:
H.tail (BigFoo "Hello" 1 2) :: Foo Foo 1 2
But if I combine the two, GHC doesn't know what to do:
H.cons "A" (H.tail (BigFoo "Hello" 1 2)) :: BigFoo
<interactive>:15:1: Couldn't match type ‘H.Elems v0’ with ‘'[Int, Int]’ The type variable ‘v0’ is ambiguous Expected type: [Char] : H.Elems v0 Actual type: H.Elems BigFoo In the expression: H.cons "A" (H.tail (BigFoo "Hello" 1 2)) :: BigFoo In an equation for ‘it’: it = H.cons "A" (H.tail (BigFoo "Hello" 1 2)) :: BigFoo
I can make it work in this case by supplying a type signature for the intermediate `tail` expression -- but what if there is no such type? Can I trick it into deducing any old type with the right shape? An intermediate tuple would work, for example.
This is problem inherent to very generic code. There could be too many types which could be assigned to intermediate extression. GHC deduce that intermediate type must be isomorphic to (Int,Int) but could not chose such type. We however can always create vector with elements of right type. Library works by converting values to Boehm-Berarducci encoding (ContVec), perform operations on and convert back to concrete representation. So we can fix type of intermediate vector to `ContVec xs` and let GHC to figure out rest. So following will work:
import qualified Data.Vector.HFixed.Cont as H (ContVec) asCont :: H.ContVec a -> H.ContVec a asCont = id
*Main> (H.cons "A" . asCont . H.tail) (BigFoo "Hello" 1 2) :: BigFoo BigFoo "A" 1 2 This function is not in the library but I'm going to add it. It is usefult for combining functions