依赖类型签名中的多态常量?
Polymorphic constant in a dependent type signature?
假设我想定义一种证明某些向量具有特定总和的证明。我还希望该证明适用于任何 Monoid
类型 t
。我的第一次尝试是这样的:
data HasSum : Monoid t => t -> Vect n t -> Type where
EndNeutral : Monoid t => HasSum Prelude.Algebra.neutral []
Component : Monoid t => (x : t) -> HasSum sum xs -> HasSum (x <+> sum) (x :: xs)
不幸的是,编译器对此提出异议Can't find implementation for Monoid t
。所以我尝试了一个隐式参数,以便我可以指定它的类型:
EndNeutral : Monoid t => {Prelude.Algebra.neutral : t} -> HasSum Prelude.Algebra.neutral []
这会编译,但不会:
x : HasSum 0 []
x = EndNeutral
st运行gely 声称它 Can't find implementation for Monoid Integer
.
我最后的尝试是用大写字母名称定义一个辅助常量,这样 Idris 就不会将它与绑定变量混淆:
ZERO : Monoid t => t
ZERO = neutral
data HasSum : Monoid t => t -> Vect n t -> Type where
EndNeutral : Monoid t => HasSum ZERO []
Component : Monoid t => {rem : t} -> (x : t) -> HasSum rem xs -> HasSum (x <+> rem) (x :: xs)
但现在它无法猜测 EndNeutral
(Can't find implementation for Monoid t
) 定义中 ZERO
的类型。所以我再次尝试使用隐式绑定:
EndNeutral : Monoid t => {ZERO : t} -> HasSum ZERO []
但现在 ZERO
变成了一个绑定变量,虽然它编译了,但它没有按预期工作,因为它允许构造一个具有任意和的空向量的证明。
此时我运行没主意了。有谁知道如何在 Idris 类型中表达多态常量?
看来我终于找到了答案。它可能不是最好的,但它是我现在所知道的唯一一个。因此需要显式指定 neutral
的类型而不添加隐式参数(这会将 neutral
变成绑定变量)。当然,函数 the
可以达到这个目的:
data HasSum : Monoid t => t -> Vect n t -> Type where
EndNeutral : Monoid t => HasSum (the t Prelude.Algebra.neutral) []
Component : Monoid t => {rem : t} -> (x : t) -> HasSum rem xs -> HasSum (x <+> rem) (x :: xs)
编辑:
查看 neutral
的类型提出了另一种解决方案:
> :doc neutral
Prelude.Algebra.neutral : Monoid ty => ty
看来 neutral
的具体类型实际上是它的隐式参数。因此:
EndNeutral : Monoid t => HasSum (Prelude.Algebra.neutral {ty = t}) []
也有效。
假设我想定义一种证明某些向量具有特定总和的证明。我还希望该证明适用于任何 Monoid
类型 t
。我的第一次尝试是这样的:
data HasSum : Monoid t => t -> Vect n t -> Type where
EndNeutral : Monoid t => HasSum Prelude.Algebra.neutral []
Component : Monoid t => (x : t) -> HasSum sum xs -> HasSum (x <+> sum) (x :: xs)
不幸的是,编译器对此提出异议Can't find implementation for Monoid t
。所以我尝试了一个隐式参数,以便我可以指定它的类型:
EndNeutral : Monoid t => {Prelude.Algebra.neutral : t} -> HasSum Prelude.Algebra.neutral []
这会编译,但不会:
x : HasSum 0 []
x = EndNeutral
st运行gely 声称它 Can't find implementation for Monoid Integer
.
我最后的尝试是用大写字母名称定义一个辅助常量,这样 Idris 就不会将它与绑定变量混淆:
ZERO : Monoid t => t
ZERO = neutral
data HasSum : Monoid t => t -> Vect n t -> Type where
EndNeutral : Monoid t => HasSum ZERO []
Component : Monoid t => {rem : t} -> (x : t) -> HasSum rem xs -> HasSum (x <+> rem) (x :: xs)
但现在它无法猜测 EndNeutral
(Can't find implementation for Monoid t
) 定义中 ZERO
的类型。所以我再次尝试使用隐式绑定:
EndNeutral : Monoid t => {ZERO : t} -> HasSum ZERO []
但现在 ZERO
变成了一个绑定变量,虽然它编译了,但它没有按预期工作,因为它允许构造一个具有任意和的空向量的证明。
此时我运行没主意了。有谁知道如何在 Idris 类型中表达多态常量?
看来我终于找到了答案。它可能不是最好的,但它是我现在所知道的唯一一个。因此需要显式指定 neutral
的类型而不添加隐式参数(这会将 neutral
变成绑定变量)。当然,函数 the
可以达到这个目的:
data HasSum : Monoid t => t -> Vect n t -> Type where
EndNeutral : Monoid t => HasSum (the t Prelude.Algebra.neutral) []
Component : Monoid t => {rem : t} -> (x : t) -> HasSum rem xs -> HasSum (x <+> rem) (x :: xs)
编辑:
查看 neutral
的类型提出了另一种解决方案:
> :doc neutral
Prelude.Algebra.neutral : Monoid ty => ty
看来 neutral
的具体类型实际上是它的隐式参数。因此:
EndNeutral : Monoid t => HasSum (Prelude.Algebra.neutral {ty = t}) []
也有效。