I want to write a function that accepts arbitrarily-nested Vect
s whose final elements are of a limited set of types incl. Double
and Integer
(the "dtype"), and the function is aware of how many Vect
s there were, and the size of each (i.e. the "shape").
For example, if my function's called const
, I want const 0.0
and const [[0.0], [1.0]]
to compile, and the type-checker know that the first has no Vect
s, and the second has two, with lengths 2 and 1. And I don't want const [["foo"], ["bar"]]
to compile.
What I've tried
- defining a type alias for nested vects and using namespaces for overloads
Array : (shape : Vect rank Nat) -> Type -> Type
Array [] ty = ty
Array (d :: ds) ty = Vect d (Array ds ty)
namespace double
const : Array shape Double -> Foo shape Double
namespace integer
const : Array shape Integer -> Foo shape Integer
but because this is slightly backwards (the compiler has to infer the type from the return type not argument of const
), this has trouble inferring the types (even for simple cases like const 0.0
) in ambiguous contexts.
- defining an interface to keep track of the shape
interface Array ty where
rank : Nat
shape : Vect rank Nat
dtype : Type
Array Double where -- same for other types
rank = 0
shape = []
dtype = Double
{len : Nat} -> Array ty => Array (Vect len ty) where
rank = 1 + rank {ty}
shape = len :: shape {ty}
dtype = dtype {ty}
const : Array ty => ty -> Foo (shape {ty}) (dtype {ty})
but this doesn't work because Idris doesn't disambiguate between Data.Vect.::
and Prelude.::
in const [0.0]
, even though I've only implemented Array
for Vect
not List
.