「SF-LC」15 Extraction
Basic Extraction
- OCaml (most mature)
- Haskell (mostly works)
- Scheme (a bit out of date)
1 | Extraction "imp1.ml" ceval_step. |
When Coq processes this command:
1 | The file imp1.ml 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:
- how the Coq type itself should be represented in OCaml
- how each constructor should be translated
1 | 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.)
1 | Extract Inductive nat ⇒ "int" |
1 | Extract Constant plus ⇒ "( + )". |
注意:保证提取结果的合理性是你的责任。
1 | Extract Constant minus ⇒ "( - )". |
比如这么做很诱人……但是我们 Coq 的定义里 0 - 1 = 0
, OCaml 的 int
则会有负数…
Recursor 的理论与实现 - a “encoding” of case expression and sum type
1 | Fixpoint ceval_step (st : state) (c : com) (i : nat) |
1 | let rec ceval_step st c = function |
1 | let rec ceval_step st c i = |
注意我们是如何使用 “recursor” 来替代 case
, match
, pattern matching 得。
recall sum type 在 PLT 中的语法与语义:
1 | T ::= |
1 | e → e' |
可以发现 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 这个 tag 的 switch 机制?
对于 Inductive nat
翻译到 OCaml int
时,这个机制可以用 v =? 0
来判断,因此我们的 recursor 实现为
1 | fun zero succ (* partial application *) |