首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用规范化器减少递归函数

使用规范化器减少递归函数
EN

Stack Overflow用户
提问于 2019-02-11 18:47:17
回答 1查看 130关注 0票数 1

我要证明一个在有限的情况下参数化的性质。我想把这个问题分成每一个案例,并分别解决每个实例。下面是一个清理事物的例子:

代码语言:javascript
复制
module Minimal
open FStar.List
open FStar.Tactics
open FStar.Reflection.Data

unfold let lst = [0;1]

unfold let prop i = 
  match i with
  | 0 -> i == 0
  | 1 -> i == 1
  | _ -> False

val propHolds (i:int) : Lemma (requires (List.mem i lst)) (ensures (prop i))

在这种情况下,情况是由列表lst定义的。我可以很容易地证明propHolds:

代码语言:javascript
复制
let propHolds i =
  assert_by_tactic (prop 0) (fun () -> norm[delta;primops;iota;zeta]; dump "normalized"; trivial ());
  assert_by_tactic (prop 1) (fun () -> norm[delta;primops;iota;zeta]; dump "normalized"; trivial ())

但我显然不想为每一种情况编写单独的assert_by_tactic (当可能有数千个..)。我想要为lst中的所有元素自动生成上述证明。

我试过很多种方法,其中之一就是:

代码语言:javascript
复制
  assert_by_tactic (let rec props i =
                       if i = 0 then prop 0
                       else (prop i) /\ (props (i-1))
                    in
                      props 1) (fun () -> norm[delta;primops;iota;zeta]; dump "normalized")

不幸的是,这并没有完全达到我想要的效果,assert_by_tactic失败了(而且没有像我所期望的那样减少)。我想我忽略了一些关于规范化的显而易见的东西,但是在F*中做这件事的标准方法是什么呢?如果解决方案指向"case"/assertion (如果存在失败的话),则奖励积分。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-02-11 22:10:57

F*的类型系统只会确保术语的弱归一化。类型良好的开放项可能会发散,例如,在不一致的上下文中减少。为了防止这种情况,F*正常化器使用各种启发式方法,默认情况下,保守地拒绝减少未还原匹配体中的递归调用。这就是为什么List.mem无法完全减少到不还原的if/s/Well的级联(if/s/ for只是布尔值匹配的糖)。

List.memP是F*的标准库中的一个相关函数,在这种情况下更易于简化,因为它不会在内部阻止未还原的匹配。注意,List.memP并不总是比List.mem--后者更容易简化,因此在某些情况下它可以计算得更多(例如,List.mem 3 [1;2;3]将很好地简化为true);

试试这个程序:

代码语言:javascript
复制
module Minimal
open FStar.Tactics

let lst = [0;1;2;3;4;5;6;7;8;9;10]

let prop i =
  match i with
  | 0 -> i == 0
  | 1 -> i == 1
  | 2 -> i == 2
  | 3 -> i == 3
  | 4 -> i == 4
  | 5 -> i == 5
  | 6 -> i == 6
  | 7 -> i == 7
  | 8 -> i == 8
  | 9 -> i == 9
  | 10 -> i == 10
  | _ -> False

let propHolds (i:int) =
  assert (List.memP i lst ==> prop i) 
      by (dump "A";
          norm [delta_only [`%List.memP; `%lst]; iota; zeta; simplify];
          dump "B")

dump B,您将看到假设被简化为嵌套的分离。Z3可以很容易地证明这个目标。

这是另一种方法,这次没有战术。

代码语言:javascript
复制
let trigger_norm (a:Type) 
  : Lemma
    (requires a)
    (ensures (Pervasives.norm [delta_only [`%List.memP; `%lst]; iota; zeta; simplify] a))
  = ()


let propHolds (i:int) 
  : Lemma
    (requires List.memP i lst)
    (ensures prop i)
  = trigger_norm (List.memP i lst)

现在,作为对jebus下面的评论的回应,您可以进一步使用一种策略来证明后置条件,尽管SMT解决程序在执行此…时非常快。因此,除非你有明确的理由这样做,否则我不会使用任何策略。

这里还有一个解决方案:

代码语言:javascript
复制
module SO
open FStar.Tactics

let lst = [0;1;2;3;4;5;6;7;8;9;10]

let pred i =
  match i with
  | 0 -> i == 0
  | 1 -> i == 1
  | 2 -> i == 2
  | 3 -> i == 3
  | 4 -> i == 4
  | 5 -> i == 5
  | 6 -> i == 6
  | 7 -> i == 7
  | 8 -> i == 8
  | 9 -> i == 9
  | 10 -> i == 10
  | _ -> False

let case_impl (a b c:Type) 
  : Lemma
    (requires (a ==> c) /\ (b ==> c))
    (ensures (a \/ b) ==> c) 
  = ()

let solve_pred_impl () : Tac unit =
    let eq = implies_intro () in
    rewrite eq;
    norm [delta_only [`%pred]; iota];
    trivial()

let test i =  
  assert (List.memP i lst ==> pred i)
      by (norm [delta_only [`%List.memP; `%lst]; iota; zeta; simplify];
          let _ = repeat 
            (fun () ->
              mapply (`case_impl); 
              split();
              solve_pred_impl()) in
          solve_pred_impl())
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/54637150

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档