The full code example below (which successfully compiles) is a simplified and slightly contrived example of my problem.
NatPair
is a pair of Nat
s, and I want to "lift" the binaryNum
operations to NatPair
pointwise, using the function lift_binary_op_to_pair
.
But I can't implement Num NatPair
because NatPair
is not a data constructor.
So, I wrap it in a type WrappedNatPair
, and I can provide a Num
implementation for that type, with corresponding 'lifted' versions of +
and *
.
Then I want to generalise the idea of a wrapper type, with my Wrapper
interface.
The function lift_natpair_bin_op_to_wrapped
can lift a binary operation from NatPair
to WrappedNatPair
, and the implementation code is entirely in terms of the unwrap
and
wrap
Wrapper
interface methods.
But, if I try to generalise to
lift_bin_op_to_wrapped : Wrapper t => BinaryOp WrappedType -> BinaryOp t
then the type signature won't even compile, with error:
`-- Wrapping.idr line 72 col 23:
When checking type of Main.lift_bin_op_to_wrapped:
Can't find implementation for Wrapper t
(where the error location is the location of ':' in the type signature).
I think the problem is that t
doesn't appear anywhere in the
type signature for the Wrapper
interface WrapperType
method,
so WrapperType
can't be invoked anywhere other than inside
the interface definition itself.
(The workaround is to write boilerplate lift_<wrapped>_bin_op_to_<wrapper>
methods with the same implementation code op x y = wrap $ op (unwrap x) (unwrap y)
each time, which is not intolerable. But I would like to have a clear understanding of why I can't write the generic lift_bin_op_to_wrapped
method.)
The full code which successfully compiles:
%default total
PairedType : (t : Type) -> Type
PairedType t = (t, t)
NatPair : Type
NatPair = PairedType Nat
data WrappedNatPair : Type where
MkWrappedNatPair : NatPair -> WrappedNatPair
equal_pair : t -> PairedType t
equal_pair x = (x, x)
BinaryOp : Type -> Type
BinaryOp t = t -> t -> t
lift_binary_op_to_pair : BinaryOp t -> BinaryOp (PairedType t)
lift_binary_op_to_pair op (x1, x2) (y1, y2) = (op x1 y1, op x2 y2)
interface Wrapper t where
WrappedType : Type
wrap : WrappedType -> t
unwrap : t -> WrappedType
Wrapper WrappedNatPair where
WrappedType = NatPair
wrap x = MkWrappedNatPair x
unwrap (MkWrappedNatPair x) = x
lift_natpair_bin_op_to_wrapped : BinaryOp NatPair -> BinaryOp WrappedNatPair
lift_natpair_bin_op_to_wrapped op x y = wrap $ op (unwrap x) (unwrap y)
Num WrappedNatPair where
(+) = lift_natpair_bin_op_to_wrapped (lift_binary_op_to_pair (+))
(*) = lift_natpair_bin_op_to_wrapped (lift_binary_op_to_pair (*))
fromInteger x = wrap $ equal_pair (fromInteger x)
WrappedNatPair_example : the WrappedNatPair 8 = (the WrappedNatPair 2) + (the WrappedNatPair 6)
WrappedNatPair_example = Refl
(Platform: Ubuntu 16.04 running Idris 1.1.1-git:83b1bed.)