微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

当参数表明结果不应该存在时的依赖型设计

如何解决当参数表明结果不应该存在时的依赖型设计

这是对 my previous question on dependently-typed arbitrarily-dimensioned matrices 的跟进。

我定义了一个矩阵类型,其中 dims 中的每个自然定义了相应维度的大小。例如,对于某些类型 Amatrix A [3; 5; 2]一个 3x5x2 矩阵:

Require Import Coq.Unicode.Utf8.
Require Export Vector.
Import VectorNotations.
Require Import List.
Import ListNotations.

Fixpoint matrix (A: Type) (dims: list nat) :=
  match dims with
  | [] => A
  | head::tail => Vector.t (matrix A tail) head
  end.

我还定义了一个 get 函数,它在指定所有索引时访问矩阵的元素:

Fixpoint get {A: Type} {dims: list nat} (m: matrix A dims) (indexes: list nat): option A :=
  if Nat.eqb (length dims) (length indexes)
  then match dims,indexes return matrix A dims → option A with
       | [],[] => λ a,Some a
       | dimh::dimt,idxh::idxt => λ m',match Fin.of_nat (idxh - 1) dimh with
           | inleft H => @get A dimt (Vector.nth m' H) idxt
           | _ => None
           end
       | _,_ => λ _,None
       end m
  else None.

现在我想支持 MATLAB 样式的索引器,其中索引是标量或范围;特殊范围 : 表示“该维度中的所有相应元素”。此函数不需要处理 MATLAB 仅指定一些索引的能力;我们将假设提供了所有索引。一些例子:

>> A = rand(3,5,2)

A(:,:,1) =

    0.8147    0.9134    0.2785    0.9649    0.9572
    0.9058    0.6324    0.5469    0.1576    0.4854
    0.1270    0.0975    0.9575    0.9706    0.8003


A(:,2) =

    0.1419    0.7922    0.0357    0.6787    0.3922
    0.4218    0.9595    0.8491    0.7577    0.6555
    0.9157    0.6557    0.9340    0.7431    0.1712

>> size(A)

ans =

     3     5     2

>> A(1,1,1)

ans =

    0.8147

>> A(1,:)       

ans(:,1) =

    0.8147


ans(:,2) =

    0.1419

>> A(1,2:4,:)

ans(:,1) =

    0.9134    0.2785    0.9649


ans(:,2) =

    0.7922    0.0357    0.6787

我可以定义表示索引器的类型:

Inductive range: Type :=
  | Scalar: nat → range
  | Subrange: nat → nat → range
  | Fullrange.

但我正在努力的地方是计算函数的结果类型。我最初的想法是定义一个函数 range_dimensions: list nat -> list range -> list nat 的想法是范围列表中的每个标量给出一个 1 的维度,每个子范围给出一个子范围大小的维度,每个完整的-range 给出维度列表对应大小的维度(第一个参数)。

但是,当列表的大小不同,或者子范围的一部分超出范围(例如,Subrange 3 5 表示大小为 4 的维度)时,返回不是一个好结果——换句话说,我更喜欢range_dimensions: list nat -> list range -> option (list nat)。但这提出了如何处理实际索引功能的问题:

Fixpoint get_range {A: Type} {dims: list nat} (m: matrix A dims) (indexes: list range): matrix A (range_dimensions dims indexes)

这行不通,因为类型不对齐。我真正想要的是返回一个 option (matrix A (range_dimensions dims indexes)),当维度计算失败时返回 None,否则返回 Some …,但我看不出有什么方法可以做到这一点。当维度列表为 option (matrix A …) 时,没有类型可用于 None

Axiom range_dimensions_ex: option (list nat)
Check match range_dimensions_ex with
      | Some dims => matrix nat dims
      | None => option (matrix nat ???)
      end.

我认为这意味着我被我在 Certified Programming with Dependent Types 中看到的东西困住了,那就是使用类似

Fixpoint get_range {A: Type} {dims: list nat} (m: matrix A dims) (indexes: list range):
match (range_dimensions dims indexes) with
| None => unit
| Some dims' => matrix A dims'
end

这似乎很难处理,尤其是考虑到到目前为止我的其他矩阵函数返回 option (matrix A …) 来表示索引失败,而不是 tt

我是不是找错了树?有没有更准确地反映我的目标的设计?请注意,这是为了将其用于 MATLAB 语义的(非常小的)子集的表达式评估函数中——如果我坚持使用 unit,否则我如何与返回 {{ 1}}?

解决方法

在 Coq 中编程的一种通用方法是将依赖类型限制在规范中,而不是在程序中使用它们。

因此,例如,矩阵可以表示为嵌套递归类型中的一对维度及其内容

Inductive matrix_ :=
| Scalar : scalar -> matrix_
| Matrix : list matrix_ -> matrix_
.

Record matrix :=
  { dim : list nat
  ; contents : matrix_
  }.

然后你需要一些谓词来指定矩阵何时是“格式良好”的:

Definition well_formed : matrix -> Prop := ...

操作将具有简单的类型:

Definition submatrix : matrix -> range -> matrix := ...

所有的复杂性都转移到规范中:

Theorem submatrix_wf (m : matrix) (r : range)
  : well_formed m -> valid_range m r -> well_formed (submatrix m r).

Theorem submatrix_dim (m : matrix) (r : range)
  : well_formed m -> valid_range m r -> dim (submatrix m r) = dim_range r.

(* etc. *)
  • 这是一个简单的表示
  • 在格式错误的输入中,您可以简单地返回垃圾而无需显式 option(而对于更结构化的表示,甚至可能没有“垃圾”的空间);如果您验证您的程序,就会发现错误。
  • 您仍然可以获得静态类型的许多好处:不会混淆矩阵、标量、布尔值、维度...

主要的权衡是使用依赖类型的丰富表示免费提供格式良好的证明,但让程序进行类型检查可能是一项非常困难的任务。使用愚蠢的表示,您只能从程序本身获得最基本的健全性检查(仍然比实际的 MATLAB 多)。但是,自动化可以在很大程度上减轻单独证明的繁琐。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?