src/Doc/Isar_Ref/HOL_Specific.thy
changeset 60675 a997fcb75d08
parent 60673 91d36d6a6a88
child 60677 7109b66ba151
equal deleted inserted replaced
60674:2f66099fb472 60675:a997fcb75d08
  2402 
  2402 
  2403 
  2403 
  2404 chapter \<open>Executable code\<close>
  2404 chapter \<open>Executable code\<close>
  2405 
  2405 
  2406 text \<open>For validation purposes, it is often useful to \emph{execute}
  2406 text \<open>For validation purposes, it is often useful to \emph{execute}
  2407   specifications.  In principle, execution could be simulated by
  2407   specifications. In principle, execution could be simulated by Isabelle's
  2408   Isabelle's inference kernel, i.e. by a combination of resolution and
  2408   inference kernel, i.e. by a combination of resolution and simplification.
  2409   simplification.  Unfortunately, this approach is rather inefficient.
  2409   Unfortunately, this approach is rather inefficient. A more efficient way
  2410   A more efficient way of executing specifications is to translate
  2410   of executing specifications is to translate them into a functional
  2411   them into a functional programming language such as ML.
  2411   programming language such as ML.
  2412 
  2412 
  2413   Isabelle provides a generic framework to support code generation
  2413   Isabelle provides a generic framework to support code generation from
  2414   from executable specifications.  Isabelle/HOL instantiates these
  2414   executable specifications. Isabelle/HOL instantiates these mechanisms in a
  2415   mechanisms in a way that is amenable to end-user applications.  Code
  2415   way that is amenable to end-user applications. Code can be generated for
  2416   can be generated for functional programs (including overloading
  2416   functional programs (including overloading using type classes) targeting
  2417   using type classes) targeting SML @{cite SML}, OCaml @{cite OCaml},
  2417   SML @{cite SML}, OCaml @{cite OCaml}, Haskell @{cite
  2418   Haskell @{cite "haskell-revised-report"} and Scala
  2418   "haskell-revised-report"} and Scala @{cite "scala-overview-tech-report"}.
  2419   @{cite "scala-overview-tech-report"}.  Conceptually, code generation is
  2419   Conceptually, code generation is split up in three steps: \emph{selection}
  2420   split up in three steps: \emph{selection} of code theorems,
  2420   of code theorems, \emph{translation} into an abstract executable view and
  2421   \emph{translation} into an abstract executable view and
  2421   \emph{serialization} to a specific \emph{target language}. Inductive
  2422   \emph{serialization} to a specific \emph{target language}.
  2422   specifications can be executed using the predicate compiler which operates
  2423   Inductive specifications can be executed using the predicate
  2423   within HOL. See @{cite "isabelle-codegen"} for an introduction.
  2424   compiler which operates within HOL.  See @{cite "isabelle-codegen"} for
       
  2425   an introduction.
       
  2426 
  2424 
  2427   \begin{matharray}{rcl}
  2425   \begin{matharray}{rcl}
  2428     @{command_def (HOL) "export_code"}@{text "\<^sup>*"} & : & @{text "context \<rightarrow>"} \\
  2426     @{command_def (HOL) "export_code"}@{text "\<^sup>*"} & : & @{text "context \<rightarrow>"} \\
  2429     @{attribute_def (HOL) code} & : & @{text attribute} \\
  2427     @{attribute_def (HOL) code} & : & @{text attribute} \\
  2430     @{command_def (HOL) "code_datatype"} & : & @{text "theory \<rightarrow> theory"} \\
  2428     @{command_def (HOL) "code_datatype"} & : & @{text "theory \<rightarrow> theory"} \\
  2446   @{rail \<open>
  2444   @{rail \<open>
  2447     @@{command (HOL) export_code} ( @'open' ) ? ( constexpr + ) \<newline>
  2445     @@{command (HOL) export_code} ( @'open' ) ? ( constexpr + ) \<newline>
  2448        ( ( @'in' target ( @'module_name' @{syntax string} ) ? \<newline>
  2446        ( ( @'in' target ( @'module_name' @{syntax string} ) ? \<newline>
  2449         ( @'file' @{syntax string} ) ? ( '(' args ')' ) ?) + ) ?
  2447         ( @'file' @{syntax string} ) ? ( '(' args ')' ) ?) + ) ?
  2450     ;
  2448     ;
  2451 
       
  2452     const: @{syntax term}
  2449     const: @{syntax term}
  2453     ;
  2450     ;
  2454 
       
  2455     constexpr: ( const | 'name._' | '_' )
  2451     constexpr: ( const | 'name._' | '_' )
  2456     ;
  2452     ;
  2457 
       
  2458     typeconstructor: @{syntax nameref}
  2453     typeconstructor: @{syntax nameref}
  2459     ;
  2454     ;
  2460 
       
  2461     class: @{syntax nameref}
  2455     class: @{syntax nameref}
  2462     ;
  2456     ;
  2463 
       
  2464     target: 'SML' | 'OCaml' | 'Haskell' | 'Scala' | 'Eval'
  2457     target: 'SML' | 'OCaml' | 'Haskell' | 'Scala' | 'Eval'
  2465     ;
  2458     ;
  2466 
       
  2467     @@{attribute (HOL) code} ( 'del' | 'equation' | 'abstype' | 'abstract'
  2459     @@{attribute (HOL) code} ( 'del' | 'equation' | 'abstype' | 'abstract'
  2468       | 'drop:' ( const + ) | 'abort:' ( const + ) )?
  2460       | 'drop:' ( const + ) | 'abort:' ( const + ) )?
  2469     ;
  2461     ;
  2470 
       
  2471     @@{command (HOL) code_datatype} ( const + )
  2462     @@{command (HOL) code_datatype} ( const + )
  2472     ;
  2463     ;
  2473 
       
  2474     @@{attribute (HOL) code_unfold} ( 'del' ) ?
  2464     @@{attribute (HOL) code_unfold} ( 'del' ) ?
  2475     ;
  2465     ;
  2476 
       
  2477     @@{attribute (HOL) code_post} ( 'del' ) ?
  2466     @@{attribute (HOL) code_post} ( 'del' ) ?
  2478     ;
  2467     ;
  2479 
       
  2480     @@{attribute (HOL) code_abbrev}
  2468     @@{attribute (HOL) code_abbrev}
  2481     ;
  2469     ;
  2482 
       
  2483     @@{command (HOL) code_thms} ( constexpr + ) ?
  2470     @@{command (HOL) code_thms} ( constexpr + ) ?
  2484     ;
  2471     ;
  2485 
       
  2486     @@{command (HOL) code_deps} ( constexpr + ) ?
  2472     @@{command (HOL) code_deps} ( constexpr + ) ?
  2487     ;
  2473     ;
  2488 
       
  2489     @@{command (HOL) code_reserved} target ( @{syntax string} + )
  2474     @@{command (HOL) code_reserved} target ( @{syntax string} + )
  2490     ;
  2475     ;
  2491 
       
  2492     symbol_const: ( @'constant' const )
  2476     symbol_const: ( @'constant' const )
  2493     ;
  2477     ;
  2494 
       
  2495     symbol_typeconstructor: ( @'type_constructor' typeconstructor )
  2478     symbol_typeconstructor: ( @'type_constructor' typeconstructor )
  2496     ;
  2479     ;
  2497 
       
  2498     symbol_class: ( @'type_class' class )
  2480     symbol_class: ( @'type_class' class )
  2499     ;
  2481     ;
  2500 
       
  2501     symbol_class_relation: ( @'class_relation' class ( '<' | '\<subseteq>' ) class )
  2482     symbol_class_relation: ( @'class_relation' class ( '<' | '\<subseteq>' ) class )
  2502     ;
  2483     ;
  2503 
       
  2504     symbol_class_instance: ( @'class_instance' typeconstructor @'::' class )
  2484     symbol_class_instance: ( @'class_instance' typeconstructor @'::' class )
  2505     ;
  2485     ;
  2506 
       
  2507     symbol_module: ( @'code_module' name )
  2486     symbol_module: ( @'code_module' name )
  2508     ;
  2487     ;
  2509 
       
  2510     syntax: @{syntax string} | ( @'infix' | @'infixl' | @'infixr' ) @{syntax nat} @{syntax string}
  2488     syntax: @{syntax string} | ( @'infix' | @'infixl' | @'infixr' ) @{syntax nat} @{syntax string}
  2511     ;
  2489     ;
  2512 
       
  2513     printing_const: symbol_const ( '\<rightharpoonup>' | '=>' ) \<newline>
  2490     printing_const: symbol_const ( '\<rightharpoonup>' | '=>' ) \<newline>
  2514       ( '(' target ')' syntax ? + @'and' )
  2491       ( '(' target ')' syntax ? + @'and' )
  2515     ;
  2492     ;
  2516 
       
  2517     printing_typeconstructor: symbol_typeconstructor ( '\<rightharpoonup>' | '=>' ) \<newline>
  2493     printing_typeconstructor: symbol_typeconstructor ( '\<rightharpoonup>' | '=>' ) \<newline>
  2518       ( '(' target ')' syntax ? + @'and' )
  2494       ( '(' target ')' syntax ? + @'and' )
  2519     ;
  2495     ;
  2520 
       
  2521     printing_class: symbol_class ( '\<rightharpoonup>' | '=>' ) \<newline>
  2496     printing_class: symbol_class ( '\<rightharpoonup>' | '=>' ) \<newline>
  2522       ( '(' target ')' @{syntax string} ? + @'and' )
  2497       ( '(' target ')' @{syntax string} ? + @'and' )
  2523     ;
  2498     ;
  2524 
       
  2525     printing_class_relation: symbol_class_relation ( '\<rightharpoonup>' | '=>' ) \<newline>
  2499     printing_class_relation: symbol_class_relation ( '\<rightharpoonup>' | '=>' ) \<newline>
  2526       ( '(' target ')' @{syntax string} ? + @'and' )
  2500       ( '(' target ')' @{syntax string} ? + @'and' )
  2527     ;
  2501     ;
  2528 
       
  2529     printing_class_instance: symbol_class_instance ( '\<rightharpoonup>' | '=>' ) \<newline>
  2502     printing_class_instance: symbol_class_instance ( '\<rightharpoonup>' | '=>' ) \<newline>
  2530       ( '(' target ')' '-' ? + @'and' )
  2503       ( '(' target ')' '-' ? + @'and' )
  2531     ;
  2504     ;
  2532 
       
  2533     printing_module: symbol_module ( '\<rightharpoonup>' | '=>' ) \<newline>
  2505     printing_module: symbol_module ( '\<rightharpoonup>' | '=>' ) \<newline>
  2534       ( '(' target ')' ( @{syntax string} ( @'attach' ( const + ) ) ? ) ? + @'and' )
  2506       ( '(' target ')' ( @{syntax string} ( @'attach' ( const + ) ) ? ) ? + @'and' )
  2535     ;
  2507     ;
  2536 
       
  2537     @@{command (HOL) code_printing} ( ( printing_const | printing_typeconstructor
  2508     @@{command (HOL) code_printing} ( ( printing_const | printing_typeconstructor
  2538       | printing_class | printing_class_relation | printing_class_instance
  2509       | printing_class | printing_class_relation | printing_class_instance
  2539       | printing_module ) + '|' )
  2510       | printing_module ) + '|' )
  2540     ;
  2511     ;
  2541 
       
  2542     @@{command (HOL) code_identifier} ( ( symbol_const | symbol_typeconstructor
  2512     @@{command (HOL) code_identifier} ( ( symbol_const | symbol_typeconstructor
  2543       | symbol_class | symbol_class_relation | symbol_class_instance
  2513       | symbol_class | symbol_class_relation | symbol_class_instance
  2544       | symbol_module ) ( '\<rightharpoonup>' | '=>' ) \<newline>
  2514       | symbol_module ) ( '\<rightharpoonup>' | '=>' ) \<newline>
  2545       ( '(' target ')' @{syntax string} ? + @'and' ) + '|' )
  2515       ( '(' target ')' @{syntax string} ? + @'and' ) + '|' )
  2546     ;
  2516     ;
  2547 
       
  2548     @@{command (HOL) code_monad} const const target
  2517     @@{command (HOL) code_monad} const const target
  2549     ;
  2518     ;
  2550 
       
  2551     @@{command (HOL) code_reflect} @{syntax string} \<newline>
  2519     @@{command (HOL) code_reflect} @{syntax string} \<newline>
  2552       ( @'datatypes' ( @{syntax string} '=' ( '_' | ( @{syntax string} + '|' ) + @'and' ) ) ) ? \<newline>
  2520       ( @'datatypes' ( @{syntax string} '=' ( '_' | ( @{syntax string} + '|' ) + @'and' ) ) ) ? \<newline>
  2553       ( @'functions' ( @{syntax string} + ) ) ? ( @'file' @{syntax string} ) ?
  2521       ( @'functions' ( @{syntax string} + ) ) ? ( @'file' @{syntax string} ) ?
  2554     ;
  2522     ;
  2555 
       
  2556     @@{command (HOL) code_pred} \<newline> ('(' @'modes' ':' modedecl ')')? \<newline> const
  2523     @@{command (HOL) code_pred} \<newline> ('(' @'modes' ':' modedecl ')')? \<newline> const
  2557     ;
  2524     ;
  2558 
       
  2559     modedecl: (modes | ((const ':' modes) \<newline>
  2525     modedecl: (modes | ((const ':' modes) \<newline>
  2560         (@'and' ((const ':' modes @'and') +))?))
  2526         (@'and' ((const ':' modes @'and') +))?))
  2561     ;
  2527     ;
  2562 
       
  2563     modes: mode @'as' const
  2528     modes: mode @'as' const
  2564   \<close>}
  2529   \<close>}
  2565 
  2530 
  2566   \begin{description}
  2531   \begin{description}
  2567 
  2532 
  2568   \item @{command (HOL) "export_code"} generates code for a given list
  2533   \item @{command (HOL) "export_code"} generates code for a given list of
  2569   of constants in the specified target language(s).  If no
  2534   constants in the specified target language(s). If no serialization
  2570   serialization instruction is given, only abstract code is generated
  2535   instruction is given, only abstract code is generated internally.
  2571   internally.
  2536 
  2572 
  2537   Constants may be specified by giving them literally, referring to all
  2573   Constants may be specified by giving them literally, referring to
  2538   executable constants within a certain theory by giving @{text "name._"},
  2574   all executable constants within a certain theory by giving @{text
  2539   or referring to \emph{all} executable constants currently available by
  2575   "name._"}, or referring to \emph{all} executable constants currently
  2540   giving @{text "_"}.
  2576   available by giving @{text "_"}.
  2541 
  2577 
  2542   By default, exported identifiers are minimized per module. This can be
  2578   By default, exported identifiers are minimized per module.  This
  2543   suppressed by prepending @{keyword "open"} before the list of constants.
  2579   can be suppressed by prepending @{keyword "open"} before the list
  2544 
  2580   of contants.
  2545   By default, for each involved theory one corresponding name space module
  2581 
  2546   is generated. Alternatively, a module name may be specified after the
  2582   By default, for each involved theory one corresponding name space
  2547   @{keyword "module_name"} keyword; then \emph{all} code is placed in this
  2583   module is generated.  Alternatively, a module name may be specified
  2548   module.
  2584   after the @{keyword "module_name"} keyword; then \emph{all} code is
       
  2585   placed in this module.
       
  2586 
  2549 
  2587   For \emph{SML}, \emph{OCaml} and \emph{Scala} the file specification
  2550   For \emph{SML}, \emph{OCaml} and \emph{Scala} the file specification
  2588   refers to a single file; for \emph{Haskell}, it refers to a whole
  2551   refers to a single file; for \emph{Haskell}, it refers to a whole
  2589   directory, where code is generated in multiple files reflecting the
  2552   directory, where code is generated in multiple files reflecting the module
  2590   module hierarchy.  Omitting the file specification denotes standard
  2553   hierarchy. Omitting the file specification denotes standard output.
  2591   output.
  2554 
  2592 
  2555   Serializers take an optional list of arguments in parentheses. For
  2593   Serializers take an optional list of arguments in parentheses.
  2556   \emph{Haskell} a module name prefix may be given using the ``@{text
  2594   For \emph{Haskell} a module name prefix may be given using the
  2557   "root:"}'' argument; ``@{text string_classes}'' adds a ``@{verbatim
  2595   ``@{text "root:"}'' argument; ``@{text string_classes}'' adds a
  2558   "deriving (Read, Show)"}'' clause to each appropriate datatype
  2596   ``@{verbatim "deriving (Read, Show)"}'' clause to each appropriate
  2559   declaration.
  2597   datatype declaration.
  2560 
  2598 
  2561   \item @{attribute (HOL) code} declare code equations for code generation.
  2599   \item @{attribute (HOL) code} declare code equations for code
  2562   Variant @{text "code equation"} declares a conventional equation as code
  2600   generation.  Variant @{text "code equation"} declares a conventional
  2563   equation. Variants @{text "code abstype"} and @{text "code abstract"}
  2601   equation as code equation.  Variants @{text "code abstype"} and
  2564   declare abstract datatype certificates or code equations on abstract
  2602   @{text "code abstract"} declare abstract datatype certificates or
  2565   datatype representations respectively. Vanilla @{text "code"} falls back
  2603   code equations on abstract datatype representations respectively.
  2566   to @{text "code equation"} or @{text "code abstype"} depending on the
  2604   Vanilla @{text "code"} falls back to @{text "code equation"}
  2567   syntactic shape of the underlying equation. Variant @{text "code del"}
  2605   or @{text "code abstype"} depending on the syntactic shape
       
  2606   of the underlying equation.  Variant @{text "code del"}
       
  2607   deselects a code equation for code generation.
  2568   deselects a code equation for code generation.
  2608 
  2569 
  2609   Variants @{text "code drop:"} and @{text "code abort:"} take
  2570   Variants @{text "code drop:"} and @{text "code abort:"} take a list of
  2610   a list of constant as arguments and drop all code equations declared
  2571   constant as arguments and drop all code equations declared for them. In
  2611   for them.  In the case of {text abort}, these constants then are
  2572   the case of {text abort}, these constants then are are not required to
  2612   are not required to have a definition by means of code equations;
  2573   have a definition by means of code equations; if needed these are
  2613   if needed these are implemented by program abort (exception) instead.
  2574   implemented by program abort (exception) instead.
  2614 
  2575 
  2615   Usually packages introducing code equations provide a reasonable
  2576   Usually packages introducing code equations provide a reasonable default
  2616   default setup for selection.
  2577   setup for selection.
  2617 
  2578 
  2618   \item @{command (HOL) "code_datatype"} specifies a constructor set
  2579   \item @{command (HOL) "code_datatype"} specifies a constructor set for a
  2619   for a logical type.
  2580   logical type.
  2620 
  2581 
  2621   \item @{command (HOL) "print_codesetup"} gives an overview on
  2582   \item @{command (HOL) "print_codesetup"} gives an overview on selected
  2622   selected code equations and code generator datatypes.
  2583   code equations and code generator datatypes.
  2623 
  2584 
  2624   \item @{attribute (HOL) code_unfold} declares (or with option
  2585   \item @{attribute (HOL) code_unfold} declares (or with option ``@{text
  2625   ``@{text "del"}'' removes) theorems which during preprocessing
  2586   "del"}'' removes) theorems which during preprocessing are applied as
  2626   are applied as rewrite rules to any code equation or evaluation
  2587   rewrite rules to any code equation or evaluation input.
  2627   input.
       
  2628 
  2588 
  2629   \item @{attribute (HOL) code_post} declares (or with option ``@{text
  2589   \item @{attribute (HOL) code_post} declares (or with option ``@{text
  2630   "del"}'' removes) theorems which are applied as rewrite rules to any
  2590   "del"}'' removes) theorems which are applied as rewrite rules to any
  2631   result of an evaluation.
  2591   result of an evaluation.
  2632 
  2592 
  2633   \item @{attribute (HOL) code_abbrev} declares (or with option ``@{text
  2593   \item @{attribute (HOL) code_abbrev} declares (or with option ``@{text
  2634   "del"}'' removes) equations which are
  2594   "del"}'' removes) equations which are applied as rewrite rules to any
  2635   applied as rewrite rules to any result of an evaluation and
  2595   result of an evaluation and symmetrically during preprocessing to any code
  2636   symmetrically during preprocessing to any code equation or evaluation
  2596   equation or evaluation input.
  2637   input.
       
  2638 
  2597 
  2639   \item @{command (HOL) "print_codeproc"} prints the setup of the code
  2598   \item @{command (HOL) "print_codeproc"} prints the setup of the code
  2640   generator preprocessor.
  2599   generator preprocessor.
  2641 
  2600 
  2642   \item @{command (HOL) "code_thms"} prints a list of theorems
  2601   \item @{command (HOL) "code_thms"} prints a list of theorems representing
  2643   representing the corresponding program containing all given
  2602   the corresponding program containing all given constants after
  2644   constants after preprocessing.
  2603   preprocessing.
  2645 
  2604 
  2646   \item @{command (HOL) "code_deps"} visualizes dependencies of
  2605   \item @{command (HOL) "code_deps"} visualizes dependencies of theorems
  2647   theorems representing the corresponding program containing all given
  2606   representing the corresponding program containing all given constants
  2648   constants after preprocessing.
  2607   after preprocessing.
  2649 
  2608 
  2650   \item @{command (HOL) "code_reserved"} declares a list of names as
  2609   \item @{command (HOL) "code_reserved"} declares a list of names as
  2651   reserved for a given target, preventing it to be shadowed by any
  2610   reserved for a given target, preventing it to be shadowed by any generated
  2652   generated code.
  2611   code.
  2653 
  2612 
  2654   \item @{command (HOL) "code_printing"} associates a series of symbols
  2613   \item @{command (HOL) "code_printing"} associates a series of symbols
  2655   (constants, type constructors, classes, class relations, instances,
  2614   (constants, type constructors, classes, class relations, instances, module
  2656   module names) with target-specific serializations; omitting a serialization
  2615   names) with target-specific serializations; omitting a serialization
  2657   deletes an existing serialization.
  2616   deletes an existing serialization.
  2658 
  2617 
  2659   \item @{command (HOL) "code_monad"} provides an auxiliary mechanism
  2618   \item @{command (HOL) "code_monad"} provides an auxiliary mechanism to
  2660   to generate monadic code for Haskell.
  2619   generate monadic code for Haskell.
  2661 
  2620 
  2662   \item @{command (HOL) "code_identifier"} associates a a series of symbols
  2621   \item @{command (HOL) "code_identifier"} associates a a series of symbols
  2663   (constants, type constructors, classes, class relations, instances,
  2622   (constants, type constructors, classes, class relations, instances, module
  2664   module names) with target-specific hints how these symbols shall be named.
  2623   names) with target-specific hints how these symbols shall be named. These
  2665   These hints gain precedence over names for symbols with no hints at all.
  2624   hints gain precedence over names for symbols with no hints at all.
  2666   Conflicting hints are subject to name disambiguation.
  2625   Conflicting hints are subject to name disambiguation. \emph{Warning:} It
  2667   \emph{Warning:} It is at the discretion
  2626   is at the discretion of the user to ensure that name prefixes of
  2668   of the user to ensure that name prefixes of identifiers in compound
  2627   identifiers in compound statements like type classes or datatypes are
  2669   statements like type classes or datatypes are still the same.
  2628   still the same.
  2670 
  2629 
  2671   \item @{command (HOL) "code_reflect"} without a ``@{text "file"}''
  2630   \item @{command (HOL) "code_reflect"} without a ``@{text "file"}''
  2672   argument compiles code into the system runtime environment and
  2631   argument compiles code into the system runtime environment and modifies
  2673   modifies the code generator setup that future invocations of system
  2632   the code generator setup that future invocations of system runtime code
  2674   runtime code generation referring to one of the ``@{text
  2633   generation referring to one of the ``@{text "datatypes"}'' or ``@{text
  2675   "datatypes"}'' or ``@{text "functions"}'' entities use these
  2634   "functions"}'' entities use these precompiled entities. With a ``@{text
  2676   precompiled entities.  With a ``@{text "file"}'' argument, the
  2635   "file"}'' argument, the corresponding code is generated into that
  2677   corresponding code is generated into that specified file without
  2636   specified file without modifying the code generator setup.
  2678   modifying the code generator setup.
  2637 
  2679 
  2638   \item @{command (HOL) "code_pred"} creates code equations for a predicate
  2680   \item @{command (HOL) "code_pred"} creates code equations for a
  2639   given a set of introduction rules. Optional mode annotations determine
  2681     predicate given a set of introduction rules. Optional mode
  2640   which arguments are supposed to be input or output. If alternative
  2682     annotations determine which arguments are supposed to be input or
  2641   introduction rules are declared, one must prove a corresponding
  2683     output. If alternative introduction rules are declared, one must
  2642   elimination rule.
  2684     prove a corresponding elimination rule.
       
  2685 
  2643 
  2686   \end{description}
  2644   \end{description}
  2687 \<close>
  2645 \<close>
  2688 
  2646 
  2689 end
  2647 end