Полный пример кода ниже (который успешно компилируется) является упрощенным и слегка надуманным примером моей проблемы.
NatPair
- это пара Nat
, и я хочу «поднять» бинарныеNum
операции до NatPair
точечно, используя функцию lift_binary_op_to_pair
.
Но я не могу реализовать Num NatPair
, потому что NatPair
не является конструктором данных.
Итак, я заключаю его в тип WrappedNatPair
и могу предоставить Num
реализацию для этого типа с соответствующими «приподнятыми» версиями +
и *
.
Затем я хочу обобщить идею типа оболочки с помощью моего Wrapper
интерфейса.
Функция lift_natpair_bin_op_to_wrapped
может поднять двоичную операцию с NatPair
до WrappedNatPair
, а код реализации полностью основан на методах интерфейса unwrap
и wrap
Wrapper
.
Но если я попытаюсь обобщить
lift_bin_op_to_wrapped : Wrapper t => BinaryOp WrappedType -> BinaryOp t
тогда подпись типа даже не скомпилируется с ошибкой:
`-- Wrapping.idr line 72 col 23:
When checking type of Main.lift_bin_op_to_wrapped:
Can't find implementation for Wrapper t
(где место ошибки - это место ":" в сигнатуре типа).
Я думаю, проблема в том, что t
нигде не фигурирует в сигнатуре типа для метода Wrapper
interface WrapperType
, поэтому WrapperType
нельзя вызывать где-либо, кроме как внутри самого определения интерфейса.
(Обходной путь состоит в том, чтобы каждый раз писать стандартные lift_<wrapped>_bin_op_to_<wrapper>
методы с одним и тем же кодом реализации op x y = wrap $ op (unwrap x) (unwrap y)
, что недопустимо. Но я хотел бы иметь четкое представление о том, почему я не могу написать общий lift_bin_op_to_wrapped
метод.)
Полный код, который успешно компилируется:
%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
(Платформа: Ubuntu 16.04 с Idris 1.1.1-git: 83b1bed.)