阅读时间约 11 分钟

「SF-LC」15 Extraction

Logical Foundations - Extracting ML From Coq

Posted by Hux on January 15, 2019
LF (逻辑基础) SF (软件基础) Coq 笔记

Basic Extraction

  • OCaml (most mature)
  • Haskell (mostly works)
  • Scheme (a bit out of date)
Extraction "imp1.ml" ceval_step.

When Coq processes this command:

The file imp1.ml has been created by extraction.
The file imp1.mli has been created by extraction.

Controlling Extraction of Specific Types

如果不做任何处理的话…生成的 ml 里的 nat 则都会是 Church Numeral…

We can tell Coq how to extract certain Inductive definitions to specific OCaml types. we must say:

  1. how the Coq type itself should be represented in OCaml
  2. how each constructor should be translated
Extract Inductive bool  "bool" [ "true" "false" ].

also, for non-enumeration types (where the constructors take arguments), we give an OCaml expression that can be used as a “recursor” over elements of the type. (Think Church numerals.)

Extract Inductive nat  "int"
  [ "0" "(fun x → x + 1)" ]
  "(fun zero succ n →
      if n=0 then zero () else succ (n-1))".
Extract Constant plus  "( + )".
Extract Constant mult  "( * )".
Extract Constant eqb  "( = )".

注意:保证提取结果的合理性是你的责任。

Extract Constant minus  "( - )".

比如这么做很诱人……但是我们 Coq 的定义里 0 - 1 = 0, OCaml 的 int 则会有负数…

Recursor 的理论与实现 - a “encoding” of case expression and sum type

Fixpoint ceval_step (st : state) (c : com) (i : nat)
                    : option state :=
  match i with
  | O => None
  | S i' =>
    match c with
let rec ceval_step st c = function
  | O -> None
  | S i' ->
    (match c with
let rec ceval_step st c i =
  (fun zero succ n -> if n=0 then zero () else succ (n-1))
    (fun _ -> None)     (* zero *)
    (fun i' ->          (* succ *)
    match c with

注意我们是如何使用 “recursor” 来替代 case, match, pattern matching 得。

recall sum type 在 PLT 中的语法与语义:

T ::= 
  T + T

e ::=
  case e of
    | L(e) => e
    | R(e) => e

                      e → e' 
                  ------------- (work inside constructor)
                  C(e) -> C(e')

                      e → e' 
          -------------------------------   (work on the expr match against)
          case e of ... →  case e' of ...

     -----------------------------------------------  (match Left constructor, substitute)
     case L(v) of L(x) => e1 | R(y) => e2 → e1 [v/x]

     -----------------------------------------------  (match Right constructor, substitute)
     case R(v) of L(x) => e1 | R(y) => e2 → e1 [v/x]

可以发现 case 表达式可以理解为一种特殊的 application,会将其 argument 根据某种 tag (这里为构造函数) apply 到对应的 case body 上, 每个 case body 都是和 lambda abstraction 同构的一种 binder:

 L(x) => e1     ===   λx.e1
 R(x) => e2     ===   λx.e2 

 case v e1|e2   ===   (λx.e1|e2) v      -- `e1` or `e2` depends on the _tag_ wrapped on `v`

这个角度也解释了 Haskell/SML 在申明函数时直接对参数写 pattern match 的理论合理性.

根据经验几乎所有的 binding 都可以被 desugar 成函数(即 lambda expression). 难点在于我们如何 re-implement 这个 tagswitch 机制?

对于 Inductive nat 翻译到 OCaml int 时,这个机制可以用 v =? 0 来判断,因此我们的 recursor 实现为

fun zero succ                (* partial application  *)
  n -> if n=0                (* 判断 tag ... *)
       then zero ()          (* 0   case =>  (λx.e1) v *)
       else succ (n-1)       (* S n case =>  (λx.e2) v *)


Testimonials

What readers say

先看读者反馈,再直接在当前页面继续讨论。公共留言需要 Waline 服务端;配置后访客只填昵称即可发布。

这类长文如果结构清楚,我会一路读到底。这里最好的地方是把概念、公式和代码示例放在同一篇里。

L
Lin 算法读者

数据库和工程文档的风格很实用,截图、SQL 和说明都能直接拿去复盘项目。

M
Mia 工程笔记党

强化学习相关文章密度很高,但排版如果更清楚,回看体验会更好。这个新版方向是对的。

R
Ryo 深夜学习者

我更喜欢能快速扫到标签、修改时间和文章重点的首页,现在这种卡片视图会比纯列表更容易选读。

C
Chen 知识整理控

代码块只要语言标识和层级做好,技术博客的专业感会立刻上来。

A
Ava 前端同行

评论区不用社交账号强绑定会更愿意留言,尤其是这种偏学习记录的网站。

N
Noah 匿名访客

Quick Identity

Pick a preset and leave a note

留言方式:先选择一个预设身份,再在下方输入评论。当前若显示“需要配置 Waline”,说明站点还缺少可写评论后端。

当前未选择预设身份

Live Discussion Waline 配置完成后,真实评论会加载在下方,移动端和主题切换会同步处理。
WALINE
Loading comments…