I'm attempting to write a thin wrapper around repa to provide extra constraints for some domain-specific work I'm doing. I have the type:
newtype Tile p r a = Tile { _array :: Array r DIM2 a }
where Array comes from repa. I'd like to hide the r because it adds noise to type signatures and makes Tile a leaky abstraction:
newtype Tile p a = Tile { _array :: Array ? DIM2 a } -- what should `?` be?
Unfortunately, that r can change between repa operations. Most of the time it's D (for "delayed representation"), but when the data is first created from a list or vector it would be U ("unboxed vector") or V ("boxed vector"). These are used as type hints to help repa optimize its operations.
Is there a way for me to hide the r as I'd like, but allow it to vary naturally internally without affecting typechecking with my wrapper Tile type? Is this the domain of RankNTypes and friends? I'll admit I don't understand them very well. To be the most clear, I'd like to be able to write:
foo :: Tile p a -> Tile p b -> Tile p c
where the two Tile arguments contain (for instance) an Array U DIM2 Int and Array D DIM2 Int respectively. Is this a bad thing to desire?
I was able to get around the issue by forcing the wrapped
Arrayto always contain theDtype param by using thedelayfunction.This also allowed me to keep
Tileas anewtypeand also define aFunctorinstance for it.