ProgTutorial/Recipes/CallML.thy
changeset 427 94538ddcac9b
child 428 c2dde8c7174f
equal deleted inserted replaced
426:d94755882e36 427:94538ddcac9b
       
     1 (*<*)
       
     2 theory CallML
       
     3 imports "~~/src/HOL/Number_Theory/Primes" Efficient_Nat
       
     4 begin
       
     5 (*>*)
       
     6 
       
     7 section {* Calling ML Functions from within HOL \label{rec:callml} *}
       
     8 
       
     9 text{* 
       
    10   {\bf Problem:} 
       
    11   How to call ML functions from within HOL?\smallskip
       
    12 
       
    13   {\bf Solution:} This can be achieved with \isacommand{code\_const}
       
    14   and \isacommand{code\_reflect}.\smallskip
       
    15 
       
    16 
       
    17   To make it clear we mean here calling unverified ML functions from within
       
    18   HOL! The motivation is the paradigm of \emph{result checking}: rather than
       
    19   verify some complicated algorithm, have the algorithm produce an easily
       
    20   checkable certificate. For example, rather than verify a primality test,
       
    21   have the test produce a factor of the input as a witness to
       
    22   non-primality. This is only an example, and we ignore the converse
       
    23   certificate, that for primality, although it, too, can be treated in the
       
    24   same manner. 
       
    25 
       
    26   The example we looking at here is an ML function for finding a factor 
       
    27   of a number. We first declare its type:
       
    28 *}
       
    29 
       
    30 consts factor :: "nat \<Rightarrow> nat"
       
    31 
       
    32 text{* 
       
    33   Its definition will be given in ML below. But the whole point is that
       
    34   we can prove non-primality via @{const factor}, no matter what its
       
    35   actual definition is: 
       
    36 *}
       
    37 
       
    38 lemma factor_non_prime:
       
    39   assumes "let k = factor n in k \<noteq> 1 \<and> k \<noteq> n \<and> k dvd n"
       
    40   shows "\<not> prime n"
       
    41 using assms by(auto simp: prime_nat_def Let_def)
       
    42 
       
    43 text{* 
       
    44   Note that the premise is executable once we have defined 
       
    45   @{const factor}. Here is a trivial definition in ML: 
       
    46 *}
       
    47 
       
    48 ML{*fun factor n = if n = 4 then 2 else 1*}
       
    49 
       
    50 text{* 
       
    51   Of course this trivial definition of @{const factor} could have been given
       
    52   directly in HOL rather than ML. But by going to the ML level, all of ML is
       
    53   at our disposal, including arrays and references, features that are less
       
    54   easily emulated in HOL. In fact, we could even call some external software
       
    55   from ML, e.g.\ a computer algebra system.
       
    56 
       
    57   It should be noted, however, that in this example you need to import the
       
    58   theory @{theory Efficient_Nat} in order to force the HOL-type @{typ nat} to
       
    59   be implemented by the ML-type @{text "int"}. Thus the ML implementation of
       
    60   @{const factor} must be and is of type @{text "int -> int"}. Now it is time
       
    61   to connect the two levels:
       
    62 *}
       
    63 
       
    64 code_const factor (SML "factor")
       
    65 
       
    66 text{* 
       
    67   The result of this declaration is that the HOL-function @{const factor} 
       
    68   is executable and command 
       
    69 *}
       
    70 
       
    71 value "factor 4"
       
    72 
       
    73 text{* 
       
    74   yields the expected result @{text 2}. Similarly we can prove that
       
    75   @{text 4} is not prime: 
       
    76 *}
       
    77 
       
    78 lemma "\<not> prime(4::nat)"
       
    79   apply(rule factor_non_prime)
       
    80   apply eval
       
    81   done
       
    82 
       
    83 text{* 
       
    84   Note, hawever, the command \isacommand{code\_const} cannot check that the ML function
       
    85   has the required type. Therefore in the worst case a type mismatch will be detected by
       
    86   the ML-compiler when we try to evaluate an expression involving @{const
       
    87   factor}. It could also happen that @{const factor} is (accidentally)
       
    88   redefined on the ML level later on. But remember that we do not assume
       
    89   anything about @{const factor} on the HOL-level. Hence no definition of
       
    90   @{const factor} can ever lead to an incorrect proof. Of course ``wrong''
       
    91   definitions can lead to compile time or run time exceptions, or to failed
       
    92   proofs.
       
    93 
       
    94   The above example was easy because we forced Iabelle (via the inclusion of @{theory
       
    95   Efficient_Nat}) to implement @{typ nat} by @{text int}, a predefined 
       
    96   ML-type.  By default, Isabelle implements, for example, the HOL-type 
       
    97   @{text list} by the corresponding ML-type. Thus the following variation 
       
    98   on @{const factor} also works: 
       
    99 *}
       
   100 
       
   101 consts factor2 :: "nat \<Rightarrow> nat list" (*<*)(*>*)
       
   102 ML{*fun factor2 n = if n = 4 then [2] else []*}(*<*)(*>*)
       
   103 code_const factor2 (SML "factor2")
       
   104 
       
   105 value "factor2 4"
       
   106 
       
   107 text{* 
       
   108   The first line declares the type of @{const factor2}; the second
       
   109   gives its implementation in ML; the third makes it executable 
       
   110   in HOL, and the last is just a test.  In this way, you can easily 
       
   111   interface with ML-functions whose types involve 
       
   112   @{text bool}, @{text int}, @{text list}, @{text option} and @{text pairs}, 
       
   113   only. If you have arbitrary tuples, for example, then you have to code 
       
   114   them as nested pairs.
       
   115 
       
   116   Let us now look at how to refer to user-defined HOL-datatypes from the
       
   117   ML-level. We modify our @{const factor} example a little by introducing a new
       
   118   datatype for the result: 
       
   119 *}
       
   120 
       
   121 datatype result = Factor nat | Prime
       
   122 
       
   123 consts factor' :: "nat \<Rightarrow> result"
       
   124 
       
   125 text{* 
       
   126   In order to write ML-code that uses this datatype, we need to define
       
   127   this datatype at the ML-level first. The following command does just that. 
       
   128 *}
       
   129 
       
   130 code_reflect Result
       
   131   datatypes result = Factor | Prime
       
   132 
       
   133 text{* 
       
   134   This creates an ML-structure called @{text Result} (the name can be
       
   135   arbitrarily chosen) that contains the datatype @{typ result}. The list 
       
   136   of constructors (but not their types) needs to be given. Now we can 
       
   137   write ML-code that uses this datatype: 
       
   138 *}
       
   139 
       
   140 ML{*fun factor' n = if n = 4 then Result.Factor 2 else Result.Prime*}
       
   141 
       
   142 text{* 
       
   143   Finally we can link the HOL and ML version of @{const factor'} as
       
   144   before: 
       
   145 *}
       
   146 
       
   147 code_const factor' (SML "factor'")
       
   148 
       
   149 text{* 
       
   150   Now any evaluation of the HOL function @{const factor'} will use the
       
   151   corresponding ML-function, like in the examples for @{const factor} above.
       
   152 
       
   153   In general, \isacommand{code\_reflect} can export multiple datatypes 
       
   154   (separated by \isacommand{and}) and also HOL-functions: simply add a line
       
   155   \isacommand{functions} $f_1$ $f_2$ and so on.
       
   156 *}
       
   157 
       
   158 (*<*)
       
   159 value "factor' 4"
       
   160 
       
   161 end
       
   162 (*>*)