src/HOL/BNF/Tools/bnf_fp_rec_sugar.ML
changeset 53411 ab4edf89992f
parent 53401 2101a97e6220
child 53654 8b9ea4420f81
equal deleted inserted replaced
53410:0d45f21e372d 53411:ab4edf89992f
   534   end;
   534   end;
   535 
   535 
   536 fun build_corec_args_discs disc_eqns ctr_specs =
   536 fun build_corec_args_discs disc_eqns ctr_specs =
   537   if null disc_eqns then I else
   537   if null disc_eqns then I else
   538     let
   538     let
       
   539 (*val _ = tracing ("d/p:\<cdot> " ^ space_implode "\n    \<cdot> " (map ((op ^) o
       
   540  apfst (Syntax.string_of_term @{context}) o apsnd (curry (op ^) " / " o @{make_string}))
       
   541   (ctr_specs |> map_filter (fn {disc, pred = SOME pred, ...} => SOME (disc, pred) | _ => NONE))));*)
   539       val conds = map #cond disc_eqns;
   542       val conds = map #cond disc_eqns;
   540       val fun_args = #fun_args (hd disc_eqns);
   543       val fun_args = #fun_args (hd disc_eqns);
   541       val args =
   544       val args =
   542         if length ctr_specs = 1 then []
   545         if length ctr_specs = 1 then []
   543         else if length disc_eqns = length ctr_specs then
   546         else if length disc_eqns = length ctr_specs then
   544           fst (split_last conds)
   547           fst (split_last conds)
   545         else if length disc_eqns = length ctr_specs - 1 then
   548         else if length disc_eqns = length ctr_specs - 1 then
   546           let val n = 0 upto length ctr_specs - 1
   549           let val n = 0 upto length ctr_specs - 1
   547               |> the o find_first (fn idx => not (exists (equal idx o #ctr_no) disc_eqns)) (*###*) in
   550               |> the(*###*) o find_first (fn idx => not (exists (equal idx o #ctr_no) disc_eqns)) in
   548             if n = length ctr_specs - 1 then
   551             if n = length ctr_specs - 1 then
   549               conds
   552               conds
   550             else
   553             else
   551               split_last conds
   554               split_last conds
   552               ||> HOLogic.mk_not
   555               ||> HOLogic.mk_not
   553               |>> chop n
   556               |> `(uncurry (fold (curry HOLogic.mk_conj o HOLogic.mk_not)))
   554               |> (fn ((l, r), x) => l @ (x :: r))
   557               ||> chop n o fst
       
   558               |> (fn (x, (l, r)) => l @ (x :: r))
   555           end
   559           end
   556         else
   560         else
   557           0 upto length ctr_specs - 1
   561           0 upto length ctr_specs - 1
   558           |> map (fn idx => find_first (equal idx o #ctr_no) disc_eqns
   562           |> map (fn idx => find_first (equal idx o #ctr_no) disc_eqns
   559             |> Option.map #cond
   563             |> Option.map #cond
   568     end;
   572     end;
   569 
   573 
   570 fun build_corec_arg_no_call sel_eqns sel = find_first (equal sel o #sel) sel_eqns
   574 fun build_corec_arg_no_call sel_eqns sel = find_first (equal sel o #sel) sel_eqns
   571   |> try (fn SOME sel_eqn => (#fun_args sel_eqn, #rhs_term sel_eqn))
   575   |> try (fn SOME sel_eqn => (#fun_args sel_eqn, #rhs_term sel_eqn))
   572   |> the_default ([], undef_const)
   576   |> the_default ([], undef_const)
   573   |-> abs_tuple;
   577   |-> abs_tuple
       
   578   |> K;
   574 
   579 
   575 fun build_corec_arg_direct_call lthy has_call sel_eqns sel =
   580 fun build_corec_arg_direct_call lthy has_call sel_eqns sel =
   576   let
   581   let
   577     val maybe_sel_eqn = find_first (equal sel o #sel) sel_eqns
   582     val maybe_sel_eqn = find_first (equal sel o #sel) sel_eqns;
   578     fun rewrite is_end U T t =
   583     fun rewrite is_end U T t =
   579       if U = @{typ bool} then @{term True} |> has_call t ? K @{term False} (* stop? *)
   584       if U = @{typ bool} then @{term True} |> has_call t ? K @{term False} (* stop? *)
   580       else if is_end = has_call t then undef_const
   585       else if is_end = has_call t then undef_const
   581       else if is_end then t (* end *)
   586       else if is_end then t (* end *)
   582       else HOLogic.mk_tuple (snd (strip_comb t)); (* continue *)
   587       else HOLogic.mk_tuple (snd (strip_comb t)); (* continue *)
   585   in
   590   in
   586     if is_none maybe_sel_eqn then K I else
   591     if is_none maybe_sel_eqn then K I else
   587       abs_tuple (#fun_args (the maybe_sel_eqn)) oo massage (#rhs_term (the maybe_sel_eqn))
   592       abs_tuple (#fun_args (the maybe_sel_eqn)) oo massage (#rhs_term (the maybe_sel_eqn))
   588   end;
   593   end;
   589 
   594 
   590 fun build_corec_arg_indirect_call sel_eqns sel =
   595 fun build_corec_arg_indirect_call lthy has_call sel_eqns sel =
   591   primrec_error "indirect corecursion not implemented yet";
   596   let
       
   597     val maybe_sel_eqn = find_first (equal sel o #sel) sel_eqns;
       
   598     fun rewrite _ _ =
       
   599       let
       
   600         fun subst (Abs (v, T, b)) = Abs (v, T, subst b)
       
   601           | subst (t as _ $ _) =
       
   602             let val (u, vs) = strip_comb t in
       
   603               if is_Free u andalso has_call u then
       
   604                 Const (@{const_name Inr}, dummyT) $ (*HOLogic.mk_tuple vs*)
       
   605                   (try (foldr1 (fn (x, y) => Const (@{const_name Pair}, dummyT) $ x $ y)) vs
       
   606                     |> the_default (hd vs))
       
   607               else if try (fst o dest_Const) u = SOME @{const_name prod_case} then
       
   608                 list_comb (u |> map_types (K dummyT), map subst vs)
       
   609               else
       
   610                 list_comb (subst u, map subst vs)
       
   611             end
       
   612           | subst t = t;
       
   613       in
       
   614         subst
       
   615       end;
       
   616     fun massage rhs_term t = massage_indirect_corec_call
       
   617       lthy has_call rewrite [] (fastype_of t |> range_type) rhs_term;
       
   618   in
       
   619     if is_none maybe_sel_eqn then I else
       
   620       abs_tuple (#fun_args (the maybe_sel_eqn)) o massage (#rhs_term (the maybe_sel_eqn))
       
   621   end;
   592 
   622 
   593 fun build_corec_args_sel lthy has_call all_sel_eqns ctr_spec =
   623 fun build_corec_args_sel lthy has_call all_sel_eqns ctr_spec =
   594   let val sel_eqns = filter (equal (#ctr ctr_spec) o #ctr) all_sel_eqns in
   624   let val sel_eqns = filter (equal (#ctr ctr_spec) o #ctr) all_sel_eqns in
   595     if null sel_eqns then I else
   625     if null sel_eqns then I else
   596       let
   626       let
   597         val sel_call_list = #sels ctr_spec ~~ #calls ctr_spec;
   627         val sel_call_list = #sels ctr_spec ~~ #calls ctr_spec;
   598 
   628 
   599 val _ = tracing ("sels / calls:\n    \<cdot> " ^ space_implode "\n    \<cdot> " (map ((op ^) o
   629 (*val _ = tracing ("s/c:\<cdot> " ^ space_implode "\n    \<cdot> " (map ((op ^) o
   600  apfst (Syntax.string_of_term @{context}) o apsnd (curry (op ^) " / " o @{make_string}))
   630  apfst (Syntax.string_of_term lthy) o apsnd (curry (op ^) " / " o @{make_string}))
   601   (sel_call_list)));
   631   sel_call_list));*)
   602 
   632 
   603         val no_calls' = map_filter (try (apsnd (fn No_Corec n => n))) sel_call_list;
   633         val no_calls' = map_filter (try (apsnd (fn No_Corec n => n))) sel_call_list;
   604         val direct_calls' = map_filter (try (apsnd (fn Direct_Corec n => n))) sel_call_list;
   634         val direct_calls' = map_filter (try (apsnd (fn Direct_Corec n => n))) sel_call_list;
   605         val indirect_calls' = map_filter (try (apsnd (fn Indirect_Corec n => n))) sel_call_list;
   635         val indirect_calls' = map_filter (try (apsnd (fn Indirect_Corec n => n))) sel_call_list;
   606       in
   636       in
   607         I
   637         I
   608         #> fold (fn (sel, n) => nth_map n
   638         #> fold (fn (sel, n) => nth_map n
   609           (build_corec_arg_no_call sel_eqns sel |> K)) no_calls'
   639           (build_corec_arg_no_call sel_eqns sel)) no_calls'
   610         #> fold (fn (sel, (q, g, h)) =>
   640         #> fold (fn (sel, (q, g, h)) =>
   611           let val f = build_corec_arg_direct_call lthy has_call sel_eqns sel in
   641           let val f = build_corec_arg_direct_call lthy has_call sel_eqns sel in
   612             nth_map h (f false) o nth_map g (f true) o nth_map q (f true) end) direct_calls'
   642             nth_map h (f false) o nth_map g (f true) o nth_map q (f true) end) direct_calls'
   613         #> fold (fn (sel, n) => nth_map n
   643         #> fold (fn (sel, n) => nth_map n
   614           (build_corec_arg_indirect_call sel_eqns sel |> K)) indirect_calls'
   644           (build_corec_arg_indirect_call lthy has_call sel_eqns sel)) indirect_calls'
   615       end
   645       end
   616   end;
   646   end;
   617 
   647 
   618 fun co_build_defs lthy sequential bs mxs has_call arg_Tss fun_name_corec_spec_list eqns_data =
   648 fun co_build_defs lthy sequential bs mxs has_call arg_Tss fun_name_corec_spec_list eqns_data =
   619   let
   649   let
   650       t $ foldr1 (fn (u, v) => HOLogic.pair_const dummyT dummyT $ u $ v)
   680       t $ foldr1 (fn (u, v) => HOLogic.pair_const dummyT dummyT $ u $ v)
   651         (length Ts - 1 downto 0 |> map Bound)
   681         (length Ts - 1 downto 0 |> map Bound)
   652       |> fold_rev (fn T => fn u => Abs (Name.uu, T, u)) Ts;
   682       |> fold_rev (fn T => fn u => Abs (Name.uu, T, u)) Ts;
   653 
   683 
   654 val _ = tracing ("corecursor arguments:\n    \<cdot> " ^
   684 val _ = tracing ("corecursor arguments:\n    \<cdot> " ^
   655  space_implode "\n    \<cdot> " (map (Syntax.string_of_term @{context}) corec_args));
   685  space_implode "\n    \<cdot> " (map (Syntax.string_of_term lthy) corec_args));
   656 
   686 
   657     fun uneq_pairs_rev xs = xs (* FIXME \<exists>? *)
   687     fun uneq_pairs_rev xs = xs (* FIXME \<exists>? *)
   658       |> these o try (split_last #> (fn (ys, y) => uneq_pairs_rev ys @ map (pair y) ys));
   688       |> these o try (split_last #> (fn (ys, y) => uneq_pairs_rev ys @ map (pair y) ys));
   659     val proof_obligations = if sequential then [] else
   689     val proof_obligations = if sequential then [] else
   660       maps (uneq_pairs_rev o map (fn {fun_args, cond, ...} => (fun_args, cond))) disc_eqnss
   690       disc_eqnss
       
   691       |> maps (uneq_pairs_rev o map (fn {fun_args, cond, ...} => (fun_args, cond)))
   661       |> map (fn ((fun_args, x), (_, y)) => [x, HOLogic.mk_not y]
   692       |> map (fn ((fun_args, x), (_, y)) => [x, HOLogic.mk_not y]
   662         |> map (HOLogic.mk_Trueprop o curry subst_bounds (List.rev fun_args))
   693         |> map (HOLogic.mk_Trueprop o curry subst_bounds (List.rev fun_args))
   663         |> curry list_comb @{const ==>});
   694         |> curry list_comb @{const ==>});
   664 
   695 
   665 val _ = tracing ("proof obligations:\n    \<cdot> " ^
   696 val _ = tracing ("proof obligations:\n    \<cdot> " ^
   666  space_implode "\n    \<cdot> " (map (Syntax.string_of_term @{context}) proof_obligations));
   697  space_implode "\n    \<cdot> " (map (Syntax.string_of_term lthy) proof_obligations));
   667 
   698 
   668   in
   699   in
   669     map (list_comb o rpair corec_args) corecs
   700     map (list_comb o rpair corec_args) corecs
   670     |> map2 (fn Ts => fn t => if length Ts = 0 then t $ HOLogic.unit else t) arg_Tss
   701     |> map2 (fn Ts => fn t => if length Ts = 0 then t $ HOLogic.unit else t) arg_Tss
   671     |> map2 currys arg_Tss
   702     |> map2 currys arg_Tss