ProgTutorial/FirstSteps.thy
changeset 328 c0cae24b9d46
parent 327 ce754ad78bc9
child 329 5dffcab68680
equal deleted inserted replaced
327:ce754ad78bc9 328:c0cae24b9d46
    55   inside the \isacommand{ML}-command can also contain value and function
    55   inside the \isacommand{ML}-command can also contain value and function
    56   bindings, for example
    56   bindings, for example
    57 *}
    57 *}
    58 
    58 
    59 ML %gray {* 
    59 ML %gray {* 
    60   val r = ref 0
    60   val r = Unsynchronized.ref 0
    61   fun f n = n + 1 
    61   fun f n = n + 1 
    62 *}
    62 *}
    63 
    63 
    64 text {*
    64 text {*
    65   and even those can be undone when the proof script is retracted.  As
    65   and even those can be undone when the proof script is retracted.  As
   272 text {*
   272 text {*
   273   Theorems also include schematic variables, such as @{text "?P"}, 
   273   Theorems also include schematic variables, such as @{text "?P"}, 
   274   @{text "?Q"} and so on. They are needed in order to able to
   274   @{text "?Q"} and so on. They are needed in order to able to
   275   instantiate theorems when they are applied. For example the theorem 
   275   instantiate theorems when they are applied. For example the theorem 
   276   @{thm [source] conjI} shown below can be used for any (typable) 
   276   @{thm [source] conjI} shown below can be used for any (typable) 
   277   instantiation of @{text "?P"} and @{text "?Q"} 
   277   instantiation of @{text "?P"} and @{text "?Q"}. 
   278 
   278 
   279   @{ML_response_fake [display, gray]
   279   @{ML_response_fake [display, gray]
   280   "tracing (string_of_thm @{context} @{thm conjI})"
   280   "tracing (string_of_thm @{context} @{thm conjI})"
   281   "\<lbrakk>?P; ?Q\<rbrakk> \<Longrightarrow> ?P \<and> ?Q"}
   281   "\<lbrakk>?P; ?Q\<rbrakk> \<Longrightarrow> ?P \<and> ?Q"}
   282 
   282 
   842   for most antiquotations. Most of the basic operations on ML-syntax are implemented 
   842   for most antiquotations. Most of the basic operations on ML-syntax are implemented 
   843   in @{ML_file "Pure/ML/ml_syntax.ML"}.
   843   in @{ML_file "Pure/ML/ml_syntax.ML"}.
   844   \end{readmore}
   844   \end{readmore}
   845 *}
   845 *}
   846 
   846 
   847 section {* Storing Data in Isabelle *}
   847 section {* Storing Data in Isabelle\label{sec:storing} *}
   848 
   848 
   849 text {*
   849 text {*
   850   Isabelle provides mechanisms for storing (and retrieving) arbitrary
   850   Isabelle provides mechanisms for storing (and retrieving) arbitrary
   851   data. Before we delve into the details, let us digress a bit. Conventional
   851   data. Before we delve into the details, let us digress a bit. Conventional
   852   wisdom has it that the type-system of ML ensures that for example an
   852   wisdom has it that the type-system of ML ensures that for example an
   912 "*** Exception- Match raised"}
   912 "*** Exception- Match raised"}
   913 
   913 
   914   This runtime error is the reason why ML is still type-sound despite
   914   This runtime error is the reason why ML is still type-sound despite
   915   containing a universal type.
   915   containing a universal type.
   916 
   916 
   917   Now, Isabelle heavily uses this mechanism to store all sorts of data: theorem lists,
   917   Now, Isabelle heavily uses this mechanism for storing all sorts of
   918   simpsets, facts etc.  Roughly speaking, there are two places where data can 
   918   data: theorem lists, simpsets, facts etc.  Roughly speaking, there are two
   919   be stored: in \emph{theories} and in \emph{proof contexts}. Again
   919   places where data can be stored: in \emph{theories} and in \emph{proof
   920   roughly speaking, data such as simpsets need to be stored in a theory,
   920   contexts}. Again roughly speaking, data such as simpsets need to be stored
   921   since they need to be maintained across proofs and even theories.
   921   in a theory, since they need to be maintained across proofs and even across
   922   On the other hands, data such as facts change inside a proof and
   922   theories.  On the other hand, data such as facts change inside a proof and
   923   therefore need to be maintained inside a proof 
   923   are only relevant to the proof at hand. Therefore such data needs to be 
   924   context.\footnote{\bf TODO: explain more bout this.} 
   924   maintained inside a proof context.\footnote{\bf TODO: explain more about 
   925 
   925   this in a separate section.}
   926   For both theories and proof contexts there are convenient functors that help
   926 
       
   927   For theories and proof contexts there are, respectively, the functors 
       
   928   @{ML_funct_ind TheoryDataFun} and @{ML_funct_ind ProofDataFun} that help
   927   with the data storage. Below we show how to implement a table in which we
   929   with the data storage. Below we show how to implement a table in which we
   928   can store theorems that can be looked up according to a string key. The
   930   can store theorems and look them up according to a string key. The
   929   intention is to be able to look up introduction rules for logical
   931   intention is to be able to look up introduction rules for logical
   930   connectives. Such a table might be useful in an automatic proof procedure
   932   connectives. Such a table might be useful in an automatic proof procedure
   931   and therefore it makes sense to store this data inside a theory.  The code
   933   and therefore it makes sense to store this data inside a theory.  The code
   932   for the table is:
   934   for the table is:
   933 *}
   935 *}
   947   the data storage (Line 3), how to copy it (Line 4), how to extend it (Line
   949   the data storage (Line 3), how to copy it (Line 4), how to extend it (Line
   948   5) and how two tables should be merged (Line 6). These functions correspond
   950   5) and how two tables should be merged (Line 6). These functions correspond
   949   roughly to the operations performed on theories.\footnote{\bf FIXME: Say more
   951   roughly to the operations performed on theories.\footnote{\bf FIXME: Say more
   950   about the assumptions of these operations.} The result structure @{ML_text Data}
   952   about the assumptions of these operations.} The result structure @{ML_text Data}
   951   contains functions for accessing the table (@{ML Data.get}) and for updating
   953   contains functions for accessing the table (@{ML Data.get}) and for updating
   952   it (@{ML Data.map}). There are also two more functions, which however we
   954   it (@{ML Data.map}). There are also two more functions (@{ML Data.init} and 
   953   ignore here. Below we define two auxiliary functions, which help us with
   955   @{ML Data.put}), which however we ignore here. Below we define two auxiliary 
   954   accessing the table.
   956   functions, which help us with accessing the table.
   955 *}
   957 *}
   956 
   958 
   957 ML{*val lookup = Symtab.lookup o Data.get
   959 ML{*val lookup = Symtab.lookup o Data.get
   958 fun update k v = Data.map (Symtab.update (k, v))*}
   960 fun update k v = Data.map (Symtab.update (k, v))*}
   959 
   961 
   967   update "op -->" @{thm impI}  #>
   969   update "op -->" @{thm impI}  #>
   968   update "All"    @{thm allI}
   970   update "All"    @{thm allI}
   969 *}
   971 *}
   970 
   972 
   971 text {*
   973 text {*
   972   The use of \isacommand{setup} makes sure the table in the current theory 
   974   The use of the command \isacommand{setup} makes sure the table in the 
   973   is updated. The lookup can now be performed as follows.
   975   \emph{current} theory is updated. The lookup can now be performed as 
       
   976   follows.
   974 
   977 
   975   @{ML_response_fake [display, gray]
   978   @{ML_response_fake [display, gray]
   976 "lookup @{theory} \"op &\""
   979 "lookup @{theory} \"op &\""
   977 "SOME \"\<lbrakk>?P; ?Q\<rbrakk> \<Longrightarrow> ?P \<and> ?Q\""}
   980 "SOME \"\<lbrakk>?P; ?Q\<rbrakk> \<Longrightarrow> ?P \<and> ?Q\""}
   978 
   981 
   982 *}
   985 *}
   983 
   986 
   984 setup %gray {* update "op &" @{thm TrueI} *}
   987 setup %gray {* update "op &" @{thm TrueI} *}
   985 
   988 
   986 text {*
   989 text {*
   987   and lookup now produces the introduction rule for @{term "True"}
   990   and @{ML lookup} now produces the introduction rule for @{term "True"}
   988   
   991   
   989 @{ML_response_fake [display, gray]
   992 @{ML_response_fake [display, gray]
   990 "lookup @{theory} \"op &\""
   993 "lookup @{theory} \"op &\""
   991 "SOME \"True\""}
   994 "SOME \"True\""}
   992 
   995 
   993   there are no references involved. This is one of the most fundamental
   996   there are no references involved. This is one of the most fundamental
   994   coding conventions for programming in Isabelle. References would interfere
   997   coding conventions for programming in Isabelle. References would 
   995   with the multithreaded execution model of Isabelle.\footnote{\bf FIXME: say more}
   998   interfere with the multithreaded execution model of Isabelle and also
   996   
   999   defeat the undo-mechanism in proof scripts. For this consider the 
       
  1000   following data container where we maintain a reference to a list of 
       
  1001   integers.
       
  1002 *}
       
  1003 
       
  1004 ML{*structure WrongRefData = TheoryDataFun
       
  1005   (type T = (int list) Unsynchronized.ref
       
  1006    val empty = Unsynchronized.ref []
       
  1007    val copy = I
       
  1008    val extend = I
       
  1009    fun merge _ = fst)*}
       
  1010 
       
  1011 text {*
       
  1012   We initialise the reference with the empty list. Consequently a first 
       
  1013   lookup produces @{ML "ref []" in Unsynchronized}.
       
  1014 
       
  1015   @{ML_response_fake [display,gray]
       
  1016   "WrongRefData.get @{theory}"
       
  1017   "ref []"}
       
  1018 
       
  1019   For updating the reference we use the following function.
       
  1020 *}
       
  1021 
       
  1022 ML{*fun ref_update n = WrongRefData.map 
       
  1023       (fn r => let val _ = r := n::(!r) in r end)*}
       
  1024 
       
  1025 text {*
       
  1026   As above we update the reference with the command 
       
  1027   \isacommand{setup}. 
       
  1028 *}
       
  1029 
       
  1030 setup %gray{* ref_update 1 *}
       
  1031 
       
  1032 text {*
       
  1033   A lookup in the current theory gives then the expected list 
       
  1034   @{ML "ref [1]" in Unsynchronized}.
       
  1035 
       
  1036   @{ML_response_fake [display,gray]
       
  1037   "WrongRefData.get @{theory}"
       
  1038   "ref [1]"}
       
  1039 
       
  1040   So far everything is as expected. But, the trouble starts if we attempt
       
  1041   to backtrack to ``before'' the \isacommand{setup}-command. There, we 
       
  1042   would expect that the list is empty again. But since it is stored in 
       
  1043   a reference, Isabelle has no control over it. So it is not
       
  1044   empty, but still @{ML "ref [1]" in Unsynchronized}. Adding to the trouble, 
       
  1045   if we execute the \isacommand{setup}-command again, we do not obtain 
       
  1046   @{ML "ref [1]" in Unsynchronized}, but
       
  1047 
       
  1048   @{ML_response_fake [display,gray]
       
  1049   "WrongRefData.get @{theory}"
       
  1050   "ref [1, 1]"}
       
  1051 
       
  1052   Now imagine how often you go backwards and forwards in your proof scripts. 
       
  1053   By using references in Isabelle code, you are bound to cause all
       
  1054   hell to break lose. Therefore observe the coding convention: 
       
  1055   Do not use references for storing data!
       
  1056 
   997   \begin{readmore}
  1057   \begin{readmore}
       
  1058   The functors for data storage are defined in @{ML_file "Pure/context.ML"}.
   998   Isabelle contains implementations of several container data structures,
  1059   Isabelle contains implementations of several container data structures,
   999   including association lists in @{ML_file "Pure/General/alist.ML"},
  1060   including association lists in @{ML_file "Pure/General/alist.ML"},
  1000   tables and symtables in @{ML_file "Pure/General/table.ML"}, and
  1061   directed graphs in @{ML_file "Pure/General/graph.ML"}. and 
  1001   directed graphs in @{ML_file "Pure/General/graph.ML"}.
  1062   tables and symtables in @{ML_file "Pure/General/table.ML"}.
  1002   \end{readmore}
  1063   \end{readmore}
  1003 
  1064 
  1004   Storing data in a proof context is similar. With the following code we
  1065   A special instance of the data storage mechanism described above are
  1005   can store a list of terms in a proof context. 
  1066   configuration values. They are used to enable users to configure tools
       
  1067   without having to resort to the ML-level (and also to avoid
       
  1068   references). Assume you want the user to control three values, say @{text
       
  1069   bval} containing a boolean, @{text ival} containing an integer and @{text
       
  1070   sval} containing a string. These values can be declared by
       
  1071 *}
       
  1072 
       
  1073 ML{*val (bval, setup_bval) = Attrib.config_bool "bval" false
       
  1074 val (ival, setup_ival) = Attrib.config_int "ival" 0
       
  1075 val (sval, setup_sval) = Attrib.config_string "sval" "some string" *}
       
  1076 
       
  1077 text {* 
       
  1078   where each value needs to be given a default. To enable these values, they need to 
       
  1079   be set up with
       
  1080 *}
       
  1081 
       
  1082 setup %gray {* 
       
  1083   setup_bval #> 
       
  1084   setup_ival 
       
  1085 *}
       
  1086 
       
  1087 text {*
       
  1088   The user can now manipulate the values from the user-level of Isabelle 
       
  1089   with the command
       
  1090 *}
       
  1091 
       
  1092 declare [[bval = true, ival = 3]]
       
  1093 
       
  1094 text {*
       
  1095   On the ML-level these values can be retrieved using the 
       
  1096   function @{ML Config.get}.
       
  1097 
       
  1098   @{ML_response [display,gray] "Config.get @{context} bval" "true"}
       
  1099 
       
  1100   \begin{readmore}
       
  1101   For more information about configuration values see 
       
  1102   @{ML_file "Pure/Isar/attrib.ML"} and @{ML_file "Pure/config.ML"}.
       
  1103   \end{readmore}
       
  1104 
       
  1105   Storing data in a proof context is done in a similar fashion. The
       
  1106   corresponding functor is @{ML_funct_ind ProofDataFun}. With the 
       
  1107   following code we can store a list of terms in a proof context. 
  1006 *}
  1108 *}
  1007 
  1109 
  1008 ML{*structure Data = ProofDataFun
  1110 ML{*structure Data = ProofDataFun
  1009   (type T = term list
  1111   (type T = term list
  1010    val init = (K []))*}
  1112    fun init _ = [])*}
  1011 
  1113 
  1012 text {*
  1114 text {*
  1013   The function we have to specify has to produce a list once a context 
  1115   The function we have to specify has to produce a list once a context 
  1014   is initialised (taking the theory into account from which the 
  1116   is initialised (taking the theory into account from which the 
  1015   context is derived). We choose to just return the empty list. Next 
  1117   context is derived). We choose to just return the empty list. Next 
  1023   case (Data.get ctxt) of
  1125   case (Data.get ctxt) of
  1024     [] => tracing "Empty!"
  1126     [] => tracing "Empty!"
  1025   | xs => tracing (string_of_terms ctxt xs)*}
  1127   | xs => tracing (string_of_terms ctxt xs)*}
  1026 
  1128 
  1027 text {*
  1129 text {*
  1028   Next we start with the context given by @{text "@{context}"} and 
  1130   Next we start with the context given by the antiquotation 
  1029   update it in various ways. 
  1131   @{text "@{context}"} and update it in various ways. 
  1030 
  1132 
  1031   @{ML_response_fake [display,gray]
  1133   @{ML_response_fake [display,gray]
  1032 "let
  1134 "let
  1033   val ctxt    = @{context}
  1135   val ctxt    = @{context}
  1034   val ctxt'   = ctxt   |> update @{term \"False\"}
  1136   val ctxt'   = ctxt   |> update @{term \"False\"}
  1047 2, 1"}
  1149 2, 1"}
  1048 
  1150 
  1049   Many functions in Isabelle manage and update data in a similar
  1151   Many functions in Isabelle manage and update data in a similar
  1050   fashion. Consequently, such calculation with contexts occur frequently in
  1152   fashion. Consequently, such calculation with contexts occur frequently in
  1051   Isabelle code, although the ``context flow'' is usually only linear.
  1153   Isabelle code, although the ``context flow'' is usually only linear.
  1052 
  1154   Note also that the calculation above has no effect on the underlying
  1053   A special instance of the mechanisms described above are configuration
  1155   theory. Once we throw away the contexts, we have no access to their
  1054   values. They are used to in order to configure tools by the user without
  1156   associated data. This is different to theories, where the command 
  1055   having to resort to the ML-level. Assume you want the user to control three
  1157   \isacommand{setup} registers the data with the current and future 
  1056   values, say @{text bval} containing a boolean, @{text ival} containing an
  1158   theories, and therefore can access the data potentially indefinitely. 
  1057   integer and @{text sval} containing a string. These values can be declared
       
  1058   by
       
  1059 *}
       
  1060 
       
  1061 ML{*val (bval, setup_bval) = Attrib.config_bool "bval" false
       
  1062 val (ival, setup_ival) = Attrib.config_int "ival" 0
       
  1063 val (sval, setup_sval) = Attrib.config_string "sval" "some string" *}
       
  1064 
       
  1065 text {* 
       
  1066   where each value needs to be given a default. To enable these values, they need to 
       
  1067   be set up with
       
  1068 *}
       
  1069 
       
  1070 setup %gray {* 
       
  1071   setup_bval #> 
       
  1072   setup_ival 
       
  1073 *}
       
  1074 
       
  1075 text {*
       
  1076   The user can now manipulate the values from the user-level of Isabelle 
       
  1077   with the command
       
  1078 *}
       
  1079 
       
  1080 declare [[bval = true, ival = 3]]
       
  1081 
       
  1082 text {*
       
  1083   On the ML-level these values can be retrieved using the 
       
  1084   function @{ML Config.get}:
       
  1085 
       
  1086   @{ML_response [display,gray] "Config.get @{context} bval" "true"}
       
  1087 
       
  1088   \begin{readmore}
       
  1089   For more information about configuration values see 
       
  1090   @{ML_file "Pure/Isar/attrib.ML"} and @{ML_file "Pure/config.ML"}.
       
  1091   \end{readmore}
       
  1092 *}
  1159 *}
  1093 
  1160 
  1094 
  1161 
  1095 
  1162 
  1096 (**************************************************)
  1163 (**************************************************)