#2 Extraction in practice : div In this section, we illustrate the use of Coq extraction on a small yet revealing example: Euclidean division amongst natural numbers. For sake of simplicity, we will use the unary nat datatype for representing these natural numbers: every number is stored as either zero or the successor S of another number. Even if this representation is inherently inefficient, the discussion that follows would be quite similar with more clever coding of numbers. Coq's Standard Library provides basic operations and relations on nat, such as +, *, <, $\leq$. In Coq, logical relations do not necessarily have corresponding boolean test functions, but here a result named le_lt_dec, noted $\leq ?$ afterwards, can be used as an effective comparison function for determining whether n $\leq$ m or m 0 | S x' => let z := div x' y in if (S z)*y ? x then S z else z end. ~~~ Knowing the quotient for the predecessor of x can indeed be used to infer the quotient for x. But proceeding this way leads to a costly test repeated x times. This is a common situation with Coq: intended algorithms can be adapted to be "structural", but this may result in an awkward and/or less efficient algorithm. xの前任者のための商を知ることはxのための商を推論するために確かに使用されるかもしれません。しかし、この方法が高価なテストヘ導く進行はx回を繰り返しました。これはCoqを備えた共通の状況です:意図したアルゴリズムは「構造の」であるのに適している場合がある。しかし、これは厄介でかつ、またはそれほど効率的でないアルゴリズムに帰着するかもしれません。 Command Extraction div can then be used to convert this division to Ocaml code: その後、コマンド抽出臆病者はこの区分をOcamlコードに変換するために使用することができます: ~~~ let rec div x y = match x with | O -> O | S x' -> let z = div x' y in if le_lt_dec (mult (S z) y) x then S z else z ~~~ This first extracted div highlights the fact that on basic Coq functions, extraction is mainly performing a straightforward syntactic translation. But even on such a simple function, some proof elimination occurs during extraction. In fact, comparison le_lt_dec a b is not producing a mere boolean, but rather a proof-carrying boolean type {a<=b}+{b bool [ true false ]. この最初の抽出された臆病者は、基礎的なCoq機能においては、抽出が主として真直ぐな構文的な翻訳を行なっているという事実を強調します。しかし、そのような単関数においてさえ、ある耐えられる除去が抽出中に生じます。実際、bが生産していない比較le_lt_dec、1つの、単なる、ブール、しかしやや証明を持ったブールのタイプ{a<=b}+{bboolを抽出する[真実、誤りの]。 One should note that the proof elimination done during extraction is based on earlier declarations by the user (or by the library designer). Here, proof-carrying boolean {a<=b}+{b fun _ _ => 0 | S n => div_F (div_loop n) end. Definition div x y := div_loop x x y. ~~~ One more time, extraction is straightforward and mostly amounts to replacing Coq keywords with Ocaml ones. The counter, whose type is nat, is kept by the extraction, even though it is morally useless for the computation. At the same time, removing it and replacing div loop by an unbounded loop would change the semantics of the program at least for y=0: with the above definition, div 5 0 computes to 5, while a Ocaml version without counter would loop forever. As a consequence, the extraction cannot be expected to detect and remove automatically such a "useless" parameter. もう1回、抽出は真直ぐで、CoqキーワードをOcamlものに取り替えることにほとんどなります。たとえそれが計算には道義的に役立たなくても、カウンター(そのタイプはnatである)は抽出によって維持されます。同時に、それを削除し臆病者ループを非束縛のループに取り替えることは、少なくともy=0 とプログラムの意味論を交換するでしょう:上記の定義で、臆病者5 0は5まで計算します。その一方でカウンターのないOcamlバージョンは永久にループしているかもしれません。結果として、抽出は、そのような「役立たない」パラメーターを自動的に検知し削除することとは予想することができません。 Using such an explicit counter is often an interesting compromise: the written Coq code is not exactly what we intended in the first place, but is close to it, there is no complex internal Coq object as with the methods we will study in the next sections, computations can be done both in Coq and after extraction, and the additional cost induced by the presence of the counter is often modest. Here for instance the x value would have been computed anyway. Another example of this technique can be found in module Numtheory of the Standard Library, where a gcd function is defined on binary numbers thanks to a counter that can be the depth (i.e. the logarithm) of these binary numbers. そのような明示的なカウンターの使用は多くの場合面白い妥協です:書かれたCoqコードはまさに私たちがまず第1に意図したものでないがそれに接近しています。私たちが次のセクションの中で勉強する方法でほど複雑な内部Coqオブジェクトはなく、計算をCoqの中で、および抽出の後に行うことができます。また、カウンターの存在によって引き起こされた追加費用は多くの場合適度です。ここで、例えば、x価値はとにかく計算されていたでしょう。この技術の別の例は、標準ライブラリー(これらの2進数の深さ(つまり対数)になりえるカウンターのおかげで2進数の上で最大公約数機能は定義される)のモジュール Numtheoryで見つけることができます。 ##2.3 A division by general recursion, historical approach We can in fact build a Coq div function that will produce exactly the intended algorithm after extraction. Before presenting the modern ways of writing such a function with two frameworks recently added to Coq, let us first mention the historical approach. For a long time, the only possibility has been to play with accessibility predicates and induction principles such as well founded induction. In this case, recursive functions do satisfy the structural constraint of Coq, not via their regular arguments, but rather via an additional logical argument expressing that some quantity is accessible. Recursive calls can then be done on quantities that are more easily accessible than before. This extra logical parameter is then meant to disappear during extraction. In practice, non-trivial functions are impossible to write as a whole with this approach, due to the numerous logical details to provide. Such functions are hence built piece by piece using Coq interactive tactics, as for proofs. Reasoning a posteriori on the body of such functions is also next to impossible, so key properties of these functions are to be attached to their output, via post-conditions { a:A | P a }. Pre-conditions can also be added to restrict functions on a certain domain: for instance, div will be defined only for y6=0. Here comes the complete specification of our div and its implementation in a proof-like style: 私たちは、抽出の後に意図したアルゴリズムを正確に生産するCoq臆病者機能を実際構築することができます。Coqに最近加えられた2つのフレームワークでそのような機能を書く現代式を示す前に、歴史上のアプローチに最初に言及しましょう。長い間、ただ一つの可能性は、よく設立された誘導のようなアクセシビリティ述語および誘導法則で遊ぶことでした。この場合、帰納的関数は、それらの規則的な議論によるではなくCoqの構造的拘束を満たします。しかし、もっと正確に言えば、論理的に議論を付加的に表現することによって、そのある量はアクセス可能です。その後、再帰呼び出しは、以前よりより容易にアクセス可能な量の上で行うことができます。その後、この余分な論理的なパラメーターは、抽出中に消えるのが目的です。実際上、このアプローチで全体として不自明な機能を書くことは、提供するべき多数の論理的な詳細により不可能です。そのような機能は証拠に関しては、ひとつひとつCoqの対話型の戦術を用いて、従って構築されます。そのような機能の主要部について帰納的に説得することはさらにあります、の隣りに、不可能、したがって、これらの機能の基本性質はポスト条件{aによって、それらの出力に付けられることになっています:1つの|P}。前条件もある領域上の機能を制限するために付け加えることができます:例えば、臆病者はy6=0のためにのみ定義されるでしょう。さあ、耐えられる類似のスタイルで私たちの臆病者とそのインプリメンテーションの完全明細書が来ました: ~~~ Definition div : 8x y, y <> 0 ! { z | z*y x < (S z)*y }. Proof. induction x as [x Hrec] using (well_founded_induction lt_wf). intros y Hy. destruct (y ? x) as [Hyx|Hyx]. (* do we have yx or x 0) { measure id x } : { z | z*y x < (S z)*y } := if y <=? x then S (div (x-y) y) else 0. Next Obligation. (* Measure decreases on recursive call : x-y < x *) unfold id; simpl; omega. Qed. Next Obligation. (* Post-condition enforcement : z*y x < (S z)*y *) destruct_call div; simpl in *; omega. Qed. ~~~ After this definition and the proofs of corresponding obligations, a Coq object div is added to the environment, mixing the pure algorithm and the logical obligations. This object is similar to the dependently-typed div of the previous section, and its extraction produces the very same Ocaml code. 対応する義務のこの定義および証拠の後、Coqオブジェクト臆病者は純粋なアルゴリズムおよび論理的な義務を混合して、環境に加えられます。このオブジェクトは前のセクションの従属的にタイプされた臆病者に似ています。また、その抽出は非常に同じOcamlコードを生産します。 Russell framework can be seen as a sort of anti-extraction, in the spirit of C. Parent's earlier works [9]. Even if it is still considered as experimental, it is already quite usable. For instance, we have a version of FSetAVL where the aforementioned non-structural operations on well-balanced trees are written and proved using Russell. ラッセル・フレームワークはC.親の初期の工場[9]の精神で一種の反抽出と見なすことができます。実験のこととまだ見なされても、それは既に全く使用可能です。例えば、ラッセルを使用して、釣合の取れている木に対する前述の非組織的なオペレーションが書かれており証明される場合、私たちは、 FSetAVLのバージョンを持っています。 ##2.5 A division by general recursion with the Function framework An alternative framework can also be used to define our div function: Function, due to J. Forest and alii [4]. It is similar to Russell to some extent: algorithms can be written in a natural way, while proof obligations may have to be solved afterwards. Here, as for Russell, these proof obligations are trivial: 代替フレームワークも私たちの臆病者機能を定義するために使用することができます:J.森林およびalii[4]による機能。それは、ラッセルにある程度まで似ています:耐えられる義務が後で解決されていなければならないかもしれない一方、アルゴリズムは自然な方法で書くことができます。ここで、ラッセルに関しては、これらの耐えられる義務は重要でありません: ~~~ Function div (x y:nat)(Hy: y <> 0) { measure id x } : nat := if y <=? x then S (div (x-y) y Hy) else 0. Proof. intros; unfold id; omega. Defined. ~~~ Moreover, as for Russell, this framework builds complex internal Coq objects, and extraction of these objects produces back precisely the expected code. But unlike Russell, Function is not meant to manipulate dependent types: in particular the y6=0 pre-condition is possible here only since it is passed unmodified to the recursive call. On the contrary, Function focuses on the ease of reasoning upon functions defined with it, see for instance the functional induction tactics, allowing to prove separately properties of div that would have been postconditions with Russell. Once again, the sensitive operations on well-balanced trees have be successfully tried and defined using Function. さらに、ラッセルに関しては、このフレームワークは複雑な内部Coqオブジェクトを構築します。また、これらのオブジェクトの抽出は後ろに正確に生産します、予期されたコード。しかし、ラッセルと異なり、機能は、依存するタイプを操作するのが目的ではありません:ただそれが再帰呼び出しに未変更に渡されるので、y6=0前条件は特に、ここで可能です。これに反して、機能はそれで定義された機能について説得する容易さに注目します、ラッセルとの postconditionsになっていたであろう臆病者の特性を別々に証明することを可能にして、例えば機能的な誘導戦術を見ます。もう一度、釣合の取れている木に対する敏感なオペレーションは持っています、成功裡に機能を使用して、試みられ定義される。