579 |
577 |
580 datatype coeqn_data = |
578 datatype coeqn_data = |
581 Disc of coeqn_data_disc | |
579 Disc of coeqn_data_disc | |
582 Sel of coeqn_data_sel; |
580 Sel of coeqn_data_sel; |
583 |
581 |
584 fun check_extra_variables lthy vars names eqn = |
582 fun is_free_in frees (Free (v, _)) = member (op =) frees v |
|
583 | is_free_in _ _ = false; |
|
584 |
|
585 fun check_extra_variables ctxt vars names eqn = |
585 let val b = fold_aterms (fn x as Free (v, _) => |
586 let val b = fold_aterms (fn x as Free (v, _) => |
586 if (not (member (op =) vars x) andalso |
587 if (not (member (op =) vars x) andalso |
587 not (member (op =) names v) andalso |
588 not (member (op =) names v) andalso |
588 v <> Name.uu_ andalso |
589 v <> Name.uu_ andalso |
589 not (Variable.is_fixed lthy v)) then cons x else I | _ => I) eqn [] |
590 not (Variable.is_fixed ctxt v)) then cons x else I | _ => I) eqn [] |
590 in |
591 in |
591 null b orelse |
592 null b orelse error_at ctxt [eqn] |
592 primcorec_error_eqn ("extra variable(s) in equation: " ^ |
593 ("Extra variable " ^ quote (Syntax.string_of_term ctxt (hd b))) |
593 commas (map (Syntax.string_of_term lthy) b)) eqn |
594 end; |
594 end; |
595 |
595 |
596 fun dissect_coeqn_disc ctxt fun_names sequentials |
596 fun dissect_coeqn_disc lthy fun_names sequentials (basic_ctr_specss : basic_corec_ctr_spec list list) |
597 (basic_ctr_specss : basic_corec_ctr_spec list list) eqn_pos ctr_rhs_opt code_rhs_opt prems0 |
597 eqn_pos ctr_rhs_opt code_rhs_opt prems' concl matchedsss = |
598 concl matchedsss = |
598 let |
599 let |
599 fun find_subterm p = |
600 fun find_subterm p = |
600 let (* FIXME \<exists>? *) |
601 let (* FIXME \<exists>? *) |
601 fun find (t as u $ v) = if p t then SOME t else merge_options (find u, find v) |
602 fun find (t as u $ v) = if p t then SOME t else merge_options (find u, find v) |
602 | find t = if p t then SOME t else NONE; |
603 | find t = if p t then SOME t else NONE; |
603 in find end; |
604 in find end; |
604 |
605 |
605 val applied_fun = concl |
606 val applied_fun = concl |
606 |> find_subterm (member (op = o apsnd SOME) fun_names o try (fst o dest_Free o head_of)) |
607 |> find_subterm (member (op = o apsnd SOME) fun_names o try (fst o dest_Free o head_of)) |
607 |> the |
608 |> the |
608 handle Option.Option => primcorec_error_eqn "malformed discriminator formula" concl; |
609 handle Option.Option => error_at ctxt [concl] "Ill-formed discriminator formula"; |
609 val ((fun_name, fun_T), fun_args) = strip_comb applied_fun |>> dest_Free; |
610 val ((fun_name, fun_T), fun_args) = strip_comb applied_fun |>> dest_Free; |
610 |
611 |
611 val fixeds = filter (Variable.is_fixed lthy o fst o dest_Free) fun_args; |
612 val fixeds = filter (Variable.is_fixed ctxt o fst o dest_Free) fun_args; |
612 val _ = null fixeds orelse |
613 val _ = null fixeds orelse error_at ctxt fixeds "Function argument(s) are fixed in context"; |
613 primcorec_error_eqns "function argument(s) are fixed in context" fixeds; |
614 |
614 |
615 val bads = filter (Term.exists_subterm (is_free_in fun_names)) prems0; |
615 val bad = |
616 val _ = null bads orelse error_at ctxt bads "Corecursive call(s) in condition(s)"; |
616 filter (exists_subterm (fn Free (v, _) => member (op =) fun_names v | _ => false)) prems'; |
|
617 val _ = null bad orelse primcorec_error_eqns "corecursive call(s) in condition(s)" bad; |
|
618 |
617 |
619 val _ = forall is_Free fun_args orelse |
618 val _ = forall is_Free fun_args orelse |
620 primcorec_error_eqn ("non-variable function argument \"" ^ |
619 error_at ctxt [applied_fun] ("Non-variable function argument \"" ^ |
621 Syntax.string_of_term lthy (find_first (not o is_Free) fun_args |> the) ^ |
620 Syntax.string_of_term ctxt (find_first (not o is_Free) fun_args |> the) ^ |
622 "\" (pattern matching is not supported by primcorec(ursive))") applied_fun |
621 "\" (pattern matching is not supported by primcorec(ursive))") |
623 |
622 |
624 val _ = let val d = duplicates (op =) fun_args in null d orelse |
623 val dups = duplicates (op =) fun_args; |
625 primcorec_error_eqn ("duplicate variable \"" ^ Syntax.string_of_term lthy (hd d) ^ "\"") |
624 val _ = |
626 applied_fun end; |
625 null dups orelse |
|
626 error_at ctxt [applied_fun] |
|
627 ("Duplicate variable " ^ quote (Syntax.string_of_term ctxt (hd dups))); |
627 |
628 |
628 val (sequential, basic_ctr_specs) = |
629 val (sequential, basic_ctr_specs) = |
629 the (AList.lookup (op =) (fun_names ~~ (sequentials ~~ basic_ctr_specss)) fun_name); |
630 the (AList.lookup (op =) (fun_names ~~ (sequentials ~~ basic_ctr_specss)) fun_name); |
630 |
631 |
631 val discs = map #disc basic_ctr_specs; |
632 val discs = map #disc basic_ctr_specs; |
632 val ctrs = map #ctr basic_ctr_specs; |
633 val ctrs = map #ctr basic_ctr_specs; |
633 val not_disc = head_of concl = @{term Not}; |
634 val not_disc = head_of concl = @{term Not}; |
634 val _ = not_disc andalso length ctrs <> 2 andalso |
635 val _ = not_disc andalso length ctrs <> 2 andalso |
635 primcorec_error_eqn "negated discriminator for a type with \<noteq> 2 constructors" concl; |
636 error_at ctxt [concl] "Negated discriminator for a type with \<noteq> 2 constructors"; |
636 val disc' = find_subterm (member (op =) discs o head_of) concl; |
637 val disc' = find_subterm (member (op =) discs o head_of) concl; |
637 val eq_ctr0 = concl |> perhaps (try HOLogic.dest_not) |> try (HOLogic.dest_eq #> snd) |
638 val eq_ctr0 = concl |> perhaps (try HOLogic.dest_not) |> try (HOLogic.dest_eq #> snd) |
638 |> (fn SOME t => let val n = find_index (curry (op =) t) ctrs in |
639 |> (fn SOME t => let val n = find_index (curry (op =) t) ctrs in |
639 if n >= 0 then SOME n else NONE end | _ => NONE); |
640 if n >= 0 then SOME n else NONE end | _ => NONE); |
640 |
641 |
641 val _ = if is_some disc' andalso perhaps (try HOLogic.dest_not) concl <> the disc' |
642 val _ = is_none disc' orelse perhaps (try HOLogic.dest_not) concl = the disc' orelse |
642 then primcorec_error_eqn "malformed discriminator formula" concl else (); |
643 error_at ctxt [concl] "Ill-formed discriminator formula"; |
643 |
|
644 val _ = is_some disc' orelse is_some eq_ctr0 orelse |
644 val _ = is_some disc' orelse is_some eq_ctr0 orelse |
645 primcorec_error_eqn "no discriminator in equation" concl; |
645 error_at ctxt [concl] "No discriminator in equation"; |
|
646 |
646 val ctr_no' = |
647 val ctr_no' = |
647 if is_none disc' then the eq_ctr0 else find_index (curry (op =) (head_of (the disc'))) discs; |
648 if is_none disc' then the eq_ctr0 else find_index (curry (op =) (head_of (the disc'))) discs; |
648 val ctr_no = if not_disc then 1 - ctr_no' else ctr_no'; |
649 val ctr_no = if not_disc then 1 - ctr_no' else ctr_no'; |
649 val {ctr, disc, ...} = nth basic_ctr_specs ctr_no; |
650 val {ctr, disc, ...} = nth basic_ctr_specs ctr_no; |
650 |
651 |
651 val catch_all = try (fst o dest_Free o the_single) prems' = SOME Name.uu_; |
652 val catch_all = (try (fst o dest_Free o the_single) prems0 = SOME Name.uu_); |
652 val matchedss = AList.lookup (op =) matchedsss fun_name |> the_default []; |
653 val matchedss = AList.lookup (op =) matchedsss fun_name |> the_default []; |
653 val prems = map (abstract (List.rev fun_args)) prems'; |
654 val prems = map (abstract (List.rev fun_args)) prems0; |
654 val actual_prems = |
655 val actual_prems = |
655 (if catch_all orelse sequential then maps s_not_conj matchedss else []) @ |
656 (if catch_all orelse sequential then maps s_not_conj matchedss else []) @ |
656 (if catch_all then [] else prems); |
657 (if catch_all then [] else prems); |
657 |
658 |
658 val matchedsss' = AList.delete (op =) fun_name matchedsss |
659 val matchedsss' = AList.delete (op =) fun_name matchedsss |
661 val user_eqn = |
662 val user_eqn = |
662 (actual_prems, concl) |
663 (actual_prems, concl) |
663 |>> map HOLogic.mk_Trueprop ||> HOLogic.mk_Trueprop o abstract (List.rev fun_args) |
664 |>> map HOLogic.mk_Trueprop ||> HOLogic.mk_Trueprop o abstract (List.rev fun_args) |
664 |> curry Logic.list_all (map dest_Free fun_args) o Logic.list_implies; |
665 |> curry Logic.list_all (map dest_Free fun_args) o Logic.list_implies; |
665 |
666 |
666 val _ = check_extra_variables lthy fun_args fun_names user_eqn; |
667 val _ = check_extra_variables ctxt fun_args fun_names user_eqn; |
667 in |
668 in |
668 (Disc {fun_name = fun_name, fun_T = fun_T, fun_args = fun_args, ctr = ctr, ctr_no = ctr_no, |
669 (Disc {fun_name = fun_name, fun_T = fun_T, fun_args = fun_args, ctr = ctr, ctr_no = ctr_no, |
669 disc = disc, prems = actual_prems, auto_gen = catch_all, ctr_rhs_opt = ctr_rhs_opt, |
670 disc = disc, prems = actual_prems, auto_gen = catch_all, ctr_rhs_opt = ctr_rhs_opt, |
670 code_rhs_opt = code_rhs_opt, eqn_pos = eqn_pos, user_eqn = user_eqn}, |
671 code_rhs_opt = code_rhs_opt, eqn_pos = eqn_pos, user_eqn = user_eqn}, |
671 matchedsss') |
672 matchedsss') |
672 end; |
673 end; |
673 |
674 |
674 fun dissect_coeqn_sel lthy fun_names (basic_ctr_specss : basic_corec_ctr_spec list list) eqn_pos |
675 fun dissect_coeqn_sel ctxt fun_names (basic_ctr_specss : basic_corec_ctr_spec list list) eqn_pos |
675 ctr_rhs_opt code_rhs_opt eqn0 of_spec_opt eqn = |
676 ctr_rhs_opt code_rhs_opt eqn0 of_spec_opt eqn = |
676 let |
677 let |
677 val (lhs, rhs) = HOLogic.dest_eq eqn |
678 val (lhs, rhs) = HOLogic.dest_eq eqn |
678 handle TERM _ => |
679 handle TERM _ => error_at ctxt [eqn] "Ill-formed equation (expected \"lhs = rhs\")"; |
679 primcorec_error_eqn "malformed function equation (expected \"lhs = rhs\")" eqn; |
|
680 val sel = head_of lhs; |
680 val sel = head_of lhs; |
681 val ((fun_name, fun_T), fun_args) = dest_comb lhs |> snd |> strip_comb |> apfst dest_Free |
681 val ((fun_name, fun_T), fun_args) = dest_comb lhs |> snd |> strip_comb |> apfst dest_Free |
682 handle TERM _ => |
682 handle TERM _ => error_at ctxt [eqn] "Ill-formed selector argument in left-hand side"; |
683 primcorec_error_eqn "malformed selector argument in left-hand side" eqn; |
683 |
684 |
684 val fixeds = filter (Variable.is_fixed ctxt o fst o dest_Free) fun_args; |
685 val _ = let val fixeds = filter (Variable.is_fixed lthy o fst o dest_Free) fun_args in |
685 val _ = |
686 null fixeds orelse primcorec_error_eqns "function argument(s) are fixed in context" fixeds |
686 null fixeds orelse error ("Function argument " ^ |
687 end; |
687 quote (Syntax.string_of_term ctxt (hd fixeds)) ^ " is fixed in context"); |
688 |
688 |
689 val basic_ctr_specs = the (AList.lookup (op =) (fun_names ~~ basic_ctr_specss) fun_name) |
689 val basic_ctr_specs = the (AList.lookup (op =) (fun_names ~~ basic_ctr_specss) fun_name) |
690 handle Option.Option => |
690 handle Option.Option => error_at ctxt [eqn] "Ill-formed selector argument in left-hand side"; |
691 primcorec_error_eqn "malformed selector argument in left-hand side" eqn; |
|
692 val {ctr, ...} = |
691 val {ctr, ...} = |
693 (case of_spec_opt of |
692 (case of_spec_opt of |
694 SOME of_spec => the (find_first (curry (op =) of_spec o #ctr) basic_ctr_specs) |
693 SOME of_spec => the (find_first (curry (op =) of_spec o #ctr) basic_ctr_specs) |
695 | NONE => filter (exists (curry (op =) sel) o #sels) basic_ctr_specs |> the_single |
694 | NONE => filter (exists (curry (op =) sel) o #sels) basic_ctr_specs |> the_single |
696 handle List.Empty => primcorec_error_eqn "ambiguous selector - use \"of\"" eqn); |
695 handle List.Empty => error_at ctxt [eqn] "Ambiguous selector (without \"of\")"); |
697 val user_eqn = drop_all eqn0; |
696 val user_eqn = drop_all eqn0; |
698 |
697 |
699 val _ = check_extra_variables lthy fun_args fun_names user_eqn; |
698 val _ = check_extra_variables ctxt fun_args fun_names user_eqn; |
700 in |
699 in |
701 Sel {fun_name = fun_name, fun_T = fun_T, fun_args = fun_args, ctr = ctr, sel = sel, |
700 Sel {fun_name = fun_name, fun_T = fun_T, fun_args = fun_args, ctr = ctr, sel = sel, |
702 rhs_term = rhs, ctr_rhs_opt = ctr_rhs_opt, code_rhs_opt = code_rhs_opt, eqn_pos = eqn_pos, |
701 rhs_term = rhs, ctr_rhs_opt = ctr_rhs_opt, code_rhs_opt = code_rhs_opt, eqn_pos = eqn_pos, |
703 user_eqn = user_eqn} |
702 user_eqn = user_eqn} |
704 end; |
703 end; |
705 |
704 |
706 fun dissect_coeqn_ctr lthy fun_names sequentials (basic_ctr_specss : basic_corec_ctr_spec list list) |
705 fun dissect_coeqn_ctr ctxt fun_names sequentials (basic_ctr_specss : basic_corec_ctr_spec list list) |
707 eqn_pos eqn0 code_rhs_opt prems concl matchedsss = |
706 eqn_pos eqn0 code_rhs_opt prems concl matchedsss = |
708 let |
707 let |
709 val (lhs, rhs) = HOLogic.dest_eq concl; |
708 val (lhs, rhs) = HOLogic.dest_eq concl; |
710 val (fun_name, fun_args) = strip_comb lhs |>> fst o dest_Free; |
709 val (fun_name, fun_args) = strip_comb lhs |>> fst o dest_Free; |
711 |
710 |
712 val _ = check_extra_variables lthy fun_args fun_names (drop_all eqn0); |
711 val _ = check_extra_variables ctxt fun_args fun_names (drop_all eqn0); |
713 |
712 |
714 val basic_ctr_specs = the (AList.lookup (op =) (fun_names ~~ basic_ctr_specss) fun_name); |
713 val basic_ctr_specs = the (AList.lookup (op =) (fun_names ~~ basic_ctr_specss) fun_name); |
715 val (ctr, ctr_args) = strip_comb (unfold_lets_splits rhs); |
714 val (ctr, ctr_args) = strip_comb (unfold_lets_splits rhs); |
716 val {disc, sels, ...} = the (find_first (curry (op =) ctr o #ctr) basic_ctr_specs) |
715 val {disc, sels, ...} = the (find_first (curry (op =) ctr o #ctr) basic_ctr_specs) |
717 handle Option.Option => primcorec_error_eqn "not a constructor" ctr; |
716 handle Option.Option => error_at ctxt [ctr] "Not a constructor"; |
718 |
717 |
719 val disc_concl = betapply (disc, lhs); |
718 val disc_concl = betapply (disc, lhs); |
720 val (eqn_data_disc_opt, matchedsss') = |
719 val (eqn_data_disc_opt, matchedsss') = |
721 if null (tl basic_ctr_specs) andalso not (null sels) then |
720 if null (tl basic_ctr_specs) andalso not (null sels) then |
722 (NONE, matchedsss) |
721 (NONE, matchedsss) |
723 else |
722 else |
724 apfst SOME (dissect_coeqn_disc lthy fun_names sequentials basic_ctr_specss eqn_pos |
723 apfst SOME (dissect_coeqn_disc ctxt fun_names sequentials basic_ctr_specss eqn_pos |
725 (SOME (abstract (List.rev fun_args) rhs)) code_rhs_opt prems disc_concl matchedsss); |
724 (SOME (abstract (List.rev fun_args) rhs)) code_rhs_opt prems disc_concl matchedsss); |
726 |
725 |
727 val sel_concls = sels ~~ ctr_args |
726 val sel_concls = sels ~~ ctr_args |
728 |> map (fn (sel, ctr_arg) => HOLogic.mk_eq (betapply (sel, lhs), ctr_arg)) |
727 |> map (fn (sel, ctr_arg) => HOLogic.mk_eq (betapply (sel, lhs), ctr_arg)) |
729 handle ListPair.UnequalLengths => |
728 handle ListPair.UnequalLengths => |
730 primcorec_error_eqn "partially applied constructor in right-hand side" rhs; |
729 error_at ctxt [rhs] "Partially applied constructor in right-hand side"; |
731 |
730 |
732 val eqns_data_sel = |
731 val eqns_data_sel = |
733 map (dissect_coeqn_sel lthy fun_names basic_ctr_specss eqn_pos |
732 map (dissect_coeqn_sel ctxt fun_names basic_ctr_specss eqn_pos |
734 (SOME (abstract (List.rev fun_args) rhs)) code_rhs_opt eqn0 (SOME ctr)) sel_concls; |
733 (SOME (abstract (List.rev fun_args) rhs)) code_rhs_opt eqn0 (SOME ctr)) sel_concls; |
735 in |
734 in |
736 (the_list eqn_data_disc_opt @ eqns_data_sel, matchedsss') |
735 (the_list eqn_data_disc_opt @ eqns_data_sel, matchedsss') |
737 end; |
736 end; |
738 |
737 |
739 fun dissect_coeqn_code lthy has_call fun_names basic_ctr_specss eqn_pos eqn0 concl matchedsss = |
738 fun dissect_coeqn_code ctxt has_call fun_names basic_ctr_specss eqn_pos eqn0 concl matchedsss = |
740 let |
739 let |
741 val (lhs, (rhs', rhs)) = HOLogic.dest_eq concl ||> `(expand_corec_code_rhs lthy has_call []); |
740 val (lhs, (rhs', rhs)) = HOLogic.dest_eq concl ||> `(expand_corec_code_rhs ctxt has_call []); |
742 val (fun_name, fun_args) = strip_comb lhs |>> fst o dest_Free; |
741 val (fun_name, fun_args) = strip_comb lhs |>> fst o dest_Free; |
743 |
742 |
744 val _ = check_extra_variables lthy fun_args fun_names concl; |
743 val _ = check_extra_variables ctxt fun_args fun_names concl; |
745 |
744 |
746 val basic_ctr_specs = the (AList.lookup (op =) (fun_names ~~ basic_ctr_specss) fun_name); |
745 val basic_ctr_specs = the (AList.lookup (op =) (fun_names ~~ basic_ctr_specss) fun_name); |
747 |
746 |
748 val cond_ctrs = fold_rev_corec_code_rhs lthy (fn cs => fn ctr => fn _ => |
747 val cond_ctrs = fold_rev_corec_code_rhs ctxt (fn cs => fn ctr => fn _ => |
749 if member (op = o apsnd #ctr) basic_ctr_specs ctr then cons (ctr, cs) |
748 if member (op = o apsnd #ctr) basic_ctr_specs ctr then cons (ctr, cs) |
750 else primcorec_error_eqn "not a constructor" ctr) [] rhs' [] |
749 else error ("Not a constructor: " ^ quote (Syntax.string_of_term ctxt ctr))) [] rhs' [] |
751 |> AList.group (op =); |
750 |> AList.group (op =); |
752 |
751 |
753 val ctr_premss = (case cond_ctrs of [_] => [[]] | _ => map (s_dnf o snd) cond_ctrs); |
752 val ctr_premss = (case cond_ctrs of [_] => [[]] | _ => map (s_dnf o snd) cond_ctrs); |
754 val ctr_concls = cond_ctrs |> map (fn (ctr, _) => |
753 val ctr_concls = cond_ctrs |> map (fn (ctr, _) => |
755 binder_types (fastype_of ctr) |
754 binder_types (fastype_of ctr) |
756 |> map_index (fn (n, T) => massage_corec_code_rhs lthy (fn _ => fn ctr' => fn args => |
755 |> map_index (fn (n, T) => massage_corec_code_rhs ctxt (fn _ => fn ctr' => fn args => |
757 if ctr' = ctr then nth args n else Const (@{const_name undefined}, T)) [] rhs') |
756 if ctr' = ctr then nth args n else Const (@{const_name undefined}, T)) [] rhs') |
758 |> curry Term.list_comb ctr |
757 |> curry Term.list_comb ctr |
759 |> curry HOLogic.mk_eq lhs); |
758 |> curry HOLogic.mk_eq lhs); |
760 |
759 |
|
760 val bads = maps (filter (Term.exists_subterm (is_free_in fun_names))) ctr_premss; |
|
761 val _ = null bads orelse unexpected_corec_call ctxt [eqn0] rhs; |
|
762 |
761 val sequentials = replicate (length fun_names) false; |
763 val sequentials = replicate (length fun_names) false; |
762 in |
764 in |
763 @{fold_map 2} (dissect_coeqn_ctr lthy fun_names sequentials basic_ctr_specss eqn_pos eqn0 |
765 @{fold_map 2} (dissect_coeqn_ctr ctxt fun_names sequentials basic_ctr_specss eqn_pos eqn0 |
764 (SOME (abstract (List.rev fun_args) rhs))) |
766 (SOME (abstract (List.rev fun_args) rhs))) |
765 ctr_premss ctr_concls matchedsss |
767 ctr_premss ctr_concls matchedsss |
766 end; |
768 end; |
767 |
769 |
768 fun dissect_coeqn lthy has_call fun_names sequentials |
770 fun dissect_coeqn ctxt has_call fun_names sequentials |
769 (basic_ctr_specss : basic_corec_ctr_spec list list) (eqn_pos, eqn0) of_spec_opt matchedsss = |
771 (basic_ctr_specss : basic_corec_ctr_spec list list) (eqn_pos, eqn0) of_spec_opt matchedsss = |
770 let |
772 let |
771 val eqn = drop_all eqn0 |
773 val eqn = drop_all eqn0 |
772 handle TERM _ => primcorec_error_eqn "malformed function equation" eqn0; |
774 handle TERM _ => error_at ctxt [eqn0] "Ill-formed function equation"; |
773 val (prems, concl) = Logic.strip_horn eqn |
775 val (prems, concl) = Logic.strip_horn eqn |
774 |> map_prod (map HOLogic.dest_Trueprop) HOLogic.dest_Trueprop |
776 |> map_prod (map HOLogic.dest_Trueprop) HOLogic.dest_Trueprop |
775 handle TERM _ => primcorec_error_eqn "malformed function equation" eqn; |
777 handle TERM _ => error_at ctxt [eqn] "Ill-formed function equation"; |
776 |
778 |
777 val head = concl |
779 val head = concl |
778 |> perhaps (try HOLogic.dest_not) |> perhaps (try (fst o HOLogic.dest_eq)) |
780 |> perhaps (try HOLogic.dest_not) |> perhaps (try (fst o HOLogic.dest_eq)) |
779 |> head_of; |
781 |> head_of; |
780 |
782 |
786 in |
788 in |
787 if member (op =) discs head orelse |
789 if member (op =) discs head orelse |
788 (is_some rhs_opt andalso |
790 (is_some rhs_opt andalso |
789 member (op =) (map SOME fun_names) (try (fst o dest_Free) head) andalso |
791 member (op =) (map SOME fun_names) (try (fst o dest_Free) head) andalso |
790 member (op =) (filter (null o binder_types o fastype_of) ctrs) (the rhs_opt)) then |
792 member (op =) (filter (null o binder_types o fastype_of) ctrs) (the rhs_opt)) then |
791 dissect_coeqn_disc lthy fun_names sequentials basic_ctr_specss eqn_pos NONE NONE prems concl |
793 dissect_coeqn_disc ctxt fun_names sequentials basic_ctr_specss eqn_pos NONE NONE prems concl |
792 matchedsss |
794 matchedsss |
793 |>> single |
795 |>> single |
794 else if member (op =) sels head then |
796 else if member (op =) sels head then |
795 (null prems orelse primcorec_error_eqn "premise(s) in selector formula" eqn; |
797 (null prems orelse error_at ctxt [eqn] "Unexpected condition in selector formula"; |
796 ([dissect_coeqn_sel lthy fun_names basic_ctr_specss eqn_pos NONE NONE eqn0 of_spec_opt |
798 ([dissect_coeqn_sel ctxt fun_names basic_ctr_specss eqn_pos NONE NONE eqn0 of_spec_opt |
797 concl], matchedsss)) |
799 concl], matchedsss)) |
798 else if is_some rhs_opt andalso |
800 else if is_some rhs_opt andalso is_Free head andalso is_free_in fun_names head then |
799 is_Free head andalso member (op =) fun_names (fst (dest_Free head)) then |
|
800 if member (op =) ctrs (head_of (unfold_lets_splits (the rhs_opt))) then |
801 if member (op =) ctrs (head_of (unfold_lets_splits (the rhs_opt))) then |
801 dissect_coeqn_ctr lthy fun_names sequentials basic_ctr_specss eqn_pos eqn0 |
802 dissect_coeqn_ctr ctxt fun_names sequentials basic_ctr_specss eqn_pos eqn0 |
802 (if null prems then |
803 (if null prems then |
803 SOME (snd (HOLogic.dest_eq (HOLogic.dest_Trueprop (Logic.strip_assums_concl eqn0)))) |
804 SOME (snd (HOLogic.dest_eq (HOLogic.dest_Trueprop (Logic.strip_assums_concl eqn0)))) |
804 else |
805 else |
805 NONE) |
806 NONE) |
806 prems concl matchedsss |
807 prems concl matchedsss |
807 else if null prems then |
808 else if null prems then |
808 dissect_coeqn_code lthy has_call fun_names basic_ctr_specss eqn_pos eqn0 concl matchedsss |
809 dissect_coeqn_code ctxt has_call fun_names basic_ctr_specss eqn_pos eqn0 concl matchedsss |
809 |>> flat |
810 |>> flat |
810 else |
811 else |
811 primcorec_error_eqn "cannot mix constructor and code views (see manual for details)" eqn |
812 error_at ctxt [eqn] "Cannot mix constructor and code views" |
812 else |
813 else |
813 primcorec_error_eqn "malformed function equation" eqn |
814 error_at ctxt [eqn] "Ill-formed function equation" |
814 end; |
815 end; |
815 |
816 |
816 fun build_corec_arg_disc (ctr_specs : corec_ctr_spec list) |
817 fun build_corec_arg_disc (ctr_specs : corec_ctr_spec list) |
817 ({fun_args, ctr_no, prems, ...} : coeqn_data_disc) = |
818 ({fun_args, ctr_no, prems, ...} : coeqn_data_disc) = |
818 if is_none (#pred (nth ctr_specs ctr_no)) then |
819 if is_none (#pred (nth ctr_specs ctr_no)) then |
827 find_first (curry (op =) sel o #sel) sel_eqns |
828 find_first (curry (op =) sel o #sel) sel_eqns |
828 |> try (fn SOME {fun_args, rhs_term, ...} => abs_tuple_balanced fun_args rhs_term) |
829 |> try (fn SOME {fun_args, rhs_term, ...} => abs_tuple_balanced fun_args rhs_term) |
829 |> the_default undef_const |
830 |> the_default undef_const |
830 |> K; |
831 |> K; |
831 |
832 |
832 fun build_corec_args_mutual_call lthy has_call (sel_eqns : coeqn_data_sel list) sel = |
833 fun build_corec_args_mutual_call ctxt has_call (sel_eqns : coeqn_data_sel list) sel = |
833 (case find_first (curry (op =) sel o #sel) sel_eqns of |
834 (case find_first (curry (op =) sel o #sel) sel_eqns of |
834 NONE => (I, I, I) |
835 NONE => (I, I, I) |
835 | SOME {fun_args, rhs_term, ... } => |
836 | SOME {fun_args, rhs_term, ... } => |
836 let |
837 let |
837 val bound_Ts = List.rev (map fastype_of fun_args); |
838 val bound_Ts = List.rev (map fastype_of fun_args); |
838 fun rewrite_stop _ t = if has_call t then @{term False} else @{term True}; |
839 fun rewrite_stop _ t = if has_call t then @{term False} else @{term True}; |
839 fun rewrite_end _ t = if has_call t then undef_const else t; |
840 fun rewrite_end _ t = if has_call t then undef_const else t; |
840 fun rewrite_cont bound_Ts t = |
841 fun rewrite_cont bound_Ts t = |
841 if has_call t then mk_tuple1_balanced bound_Ts (snd (strip_comb t)) else undef_const; |
842 if has_call t then mk_tuple1_balanced bound_Ts (snd (strip_comb t)) else undef_const; |
842 fun massage f _ = massage_let_if_case lthy has_call f bound_Ts rhs_term |
843 fun massage f _ = massage_let_if_case ctxt has_call f bound_Ts rhs_term |
843 |> abs_tuple_balanced fun_args; |
844 |> abs_tuple_balanced fun_args; |
844 in |
845 in |
845 (massage rewrite_stop, massage rewrite_end, massage rewrite_cont) |
846 (massage rewrite_stop, massage rewrite_end, massage rewrite_cont) |
846 end); |
847 end); |
847 |
848 |
848 fun build_corec_arg_nested_call lthy has_call (sel_eqns : coeqn_data_sel list) sel = |
849 fun build_corec_arg_nested_call ctxt has_call (sel_eqns : coeqn_data_sel list) sel = |
849 (case find_first (curry (op =) sel o #sel) sel_eqns of |
850 (case find_first (curry (op =) sel o #sel) sel_eqns of |
850 NONE => I |
851 NONE => I |
851 | SOME {fun_args, rhs_term, ...} => |
852 | SOME {fun_args, rhs_term, ...} => |
852 let |
853 let |
853 fun massage bound_Ts U T = |
854 fun massage bound_Ts U T = |
892 val nested_calls' = map_filter (try (apsnd (fn Nested_Corec n => n))) sel_call_list; |
893 val nested_calls' = map_filter (try (apsnd (fn Nested_Corec n => n))) sel_call_list; |
893 in |
894 in |
894 I |
895 I |
895 #> fold (fn (sel, n) => nth_map n (build_corec_arg_no_call sel_eqns sel)) no_calls' |
896 #> fold (fn (sel, n) => nth_map n (build_corec_arg_no_call sel_eqns sel)) no_calls' |
896 #> fold (fn (sel, (q, g, h)) => |
897 #> fold (fn (sel, (q, g, h)) => |
897 let val (fq, fg, fh) = build_corec_args_mutual_call lthy has_call sel_eqns sel in |
898 let val (fq, fg, fh) = build_corec_args_mutual_call ctxt has_call sel_eqns sel in |
898 nth_map q fq o nth_map g fg o nth_map h fh end) mutual_calls' |
899 nth_map q fq o nth_map g fg o nth_map h fh end) mutual_calls' |
899 #> fold (fn (sel, n) => nth_map n |
900 #> fold (fn (sel, n) => nth_map n |
900 (build_corec_arg_nested_call lthy has_call sel_eqns sel)) nested_calls' |
901 (build_corec_arg_nested_call ctxt has_call sel_eqns sel)) nested_calls' |
901 end); |
902 end); |
902 |
903 |
903 fun build_codefs lthy bs mxs has_call arg_Tss (corec_specs : corec_spec list) |
904 fun build_codefs ctxt bs mxs has_call arg_Tss (corec_specs : corec_spec list) |
904 (disc_eqnss : coeqn_data_disc list list) (sel_eqnss : coeqn_data_sel list list) = |
905 (disc_eqnss : coeqn_data_disc list list) (sel_eqnss : coeqn_data_sel list list) = |
905 let |
906 let |
906 val corecs = map #corec corec_specs; |
907 val corecs = map #corec corec_specs; |
907 val ctr_specss = map #ctr_specs corec_specs; |
908 val ctr_specss = map #ctr_specs corec_specs; |
908 val corec_args = hd corecs |
909 val corec_args = hd corecs |
909 |> fst o split_last o binder_types o fastype_of |
910 |> fst o split_last o binder_types o fastype_of |
910 |> map (fn T => |
911 |> map (fn T => |
911 if range_type T = HOLogic.boolT then Abs (Name.uu_, domain_type T, @{term False}) |
912 if range_type T = HOLogic.boolT then Abs (Name.uu_, domain_type T, @{term False}) |
912 else Const (@{const_name undefined}, T)) |
913 else Const (@{const_name undefined}, T)) |
913 |> fold2 (fold o build_corec_arg_disc) ctr_specss disc_eqnss |
914 |> fold2 (fold o build_corec_arg_disc) ctr_specss disc_eqnss |
914 |> fold2 (fold o build_corec_args_sel lthy has_call) sel_eqnss ctr_specss; |
915 |> fold2 (fold o build_corec_args_sel ctxt has_call) sel_eqnss ctr_specss; |
915 |
916 |
916 fun currys [] t = t |
917 fun currys [] t = t |
917 | currys Ts t = t $ mk_tuple1_balanced (List.rev Ts) (map Bound (length Ts - 1 downto 0)) |
918 | currys Ts t = t $ mk_tuple1_balanced (List.rev Ts) (map Bound (length Ts - 1 downto 0)) |
918 |> fold_rev (Term.abs o pair Name.uu) Ts; |
919 |> fold_rev (Term.abs o pair Name.uu) Ts; |
919 |
920 |