@@ -474,34 +474,143 @@ and reduce_exp_call env id args at = function
474474 reduce_exp_call env id args at clauses'
475475 | None -> reduce_exp_call env id args at clauses'
476476 | Some s ->
477- match reduce_prems env Subst. (subst_list subst_prem s prems) with
477+ match reduce_prems env s prems with
478478 | None -> None
479479 | Some false -> reduce_exp_call env id args at clauses'
480480 | Some true -> Some (reduce_exp env (Subst. subst_exp s e))
481481
482- and reduce_prems env = function
482+ and reduce_prems env s = function
483483 | [] -> Some true
484484 | prem ::prems ->
485- match reduce_prem env prem with
486- | Some true -> reduce_prems env prems
487- | other -> other
485+ match reduce_prem env (Subst. subst_prem s prem) with
486+ | `True s' -> reduce_prems env (Subst. union s s') prems
487+ | `False -> Some false
488+ | `None -> None
488489
489- and reduce_prem env prem : bool option =
490+ and reduce_prem env prem : [`True of Subst.t | `False | `None] =
490491 match prem.it with
491- | RulePr _ -> None
492+ | RulePr _ -> ` None
492493 | IfPr e ->
493494 (match (reduce_exp env e).it with
494- | BoolE b -> Some b
495- | _ -> None
495+ | BoolE b -> if b then `True Subst. empty else `False
496+ | _ -> ` None
496497 )
497- | ElsePr -> Some true
498+ | ElsePr -> `True Subst. empty
498499 | LetPr (e1 , e2 , _ids ) ->
499500 (match match_exp env Subst. empty e2 e1 with
500- | Some _ -> Some true (* TODO(2, rossberg): need to keep substitution? *)
501- | None -> None
502- | exception Irred -> None
501+ | Some s -> `True s
502+ | None -> ` None
503+ | exception Irred -> ` None
503504 )
504- | IterPr (_prem , _iter ) -> None (* TODO(3, rossberg): reduce? *)
505+ | IterPr (prem1 , iterexp ) ->
506+ let iter', xes' = reduce_iterexp env iterexp in
507+ (* Distinguish between let-defined variables, which flow outwards,
508+ * and others, which are assumed to flow inwards. *)
509+ let rec is_let_bound prem (x , _ ) =
510+ match prem.it with
511+ | LetPr (_ , _ , xs ) -> List. mem x.it xs
512+ | IterPr (premI , iterexpI ) ->
513+ let _iter1', xes1' = reduce_iterexp env iterexpI in
514+ let xes1_out, _ = List. partition (is_let_bound premI) xes1' in
515+ List. exists (fun (_ , e1 ) -> Free. (Set. mem x.it (free_exp e1).varid)) xes1_out
516+ | _ -> false
517+ in
518+ let xes_out, xes_in = List. partition (is_let_bound prem) xes' in
519+ let xs_out, es_out = List. split xes_out in
520+ let xs_in, es_in = List. split xes_in in
521+ if not (List. for_all is_head_normal_exp es_in) || iter' < = List1 && es_in = [] then
522+ (* We don't know the number of iterations (yet): can't do anything. *)
523+ `None
524+ else
525+ (match iter' with
526+ | Opt ->
527+ let eos_in = List. map as_opt_exp es_in in
528+ if List. for_all Option. is_none eos_in then
529+ (* Iterating over empty option: nothing to do. *)
530+ `True Subst. empty
531+ else if List. for_all Option. is_some eos_in then
532+ (* All iteration variables are non-empty: reduce body. *)
533+ let es1_in = List. map Option. get eos_in in
534+ (* s substitutes in-bound iteration variables with corresponding
535+ * values. *)
536+ let s = List. fold_left2 Subst. add_varid Subst. empty xs_in es1_in in
537+ match reduce_prem env (Subst. subst_prem s prem1) with
538+ | (`None | `False ) as r -> r
539+ | `True s' ->
540+ (* Body is true: now reverse-match out-bound iteration values
541+ * against iteration sources. *)
542+ match
543+ List. fold_left (fun s_opt (xI , eI ) ->
544+ let * s = s_opt in
545+ let tI = match eI.note.it with IterT (tI , _ ) -> tI | _ -> assert false in
546+ match_exp' env s (OptE (Some (Subst. subst_exp s' (VarE xI $$ xI.at % tI))) $> eI) eI
547+ ) (Some Subst. empty) xes_out
548+ with
549+ | Some s'' -> `True s''
550+ | None -> `None
551+ else
552+ (* Inconsistent arity of iteration values: can't perform mapping.
553+ * (This is a stuck computation, i.e., undefined.) *)
554+ `None
555+ | List | List1 ->
556+ (* Unspecified iteration count: get length from (first) iteration value
557+ * and start over; es'/es_in is in hnf, so got to be a list. *)
558+ let n = List. length (as_list_exp (List. hd es_in)) in
559+ if iter' = List || n > = 1 then
560+ let en = NumE (`Nat (Z. of_int n)) $$ prem.at % (NumT `NatT $ prem.at) in
561+ reduce_prem env (IterPr (prem1, (ListN (en, None ), xes')) $> prem)
562+ else
563+ (* List is empty although it is List1: inconsistency.
564+ * (This is a stuck computation, i.e., undefined.) *)
565+ `None
566+ | ListN ({it = NumE (`Nat n' ); _} , xo ) ->
567+ (* Iterationen values es'/es_in are in hnf, so got to be lists. *)
568+ let ess_in = List. map as_list_exp es_in in
569+ let ns = List. map List. length ess_in in
570+ let n = Z. to_int n' in
571+ if List. for_all ((= ) n) ns then
572+ (* All in-bound lists have the expected length: reduce body,
573+ * once for each tuple of values from the iterated lists. *)
574+ let rs = List. init n (fun i ->
575+ let esI_in = List. map (fun es -> List. nth es i) ess_in in
576+ (* s substitutes in-bound iteration variables with corresponding
577+ * values for this respective iteration. *)
578+ let s = List. fold_left2 Subst. add_varid Subst. empty xs_in esI_in in
579+ (* Add iteration counter variable if used. *)
580+ let s' =
581+ Option. fold xo ~none: s ~some: (fun x ->
582+ let en = NumE (`Nat (Z. of_int i)) $$ x.at % (NumT `NatT $ x.at) in
583+ Subst. add_varid s x en
584+ )
585+ in
586+ reduce_prem env (Subst. subst_prem s' prem1)
587+ )
588+ in
589+ if List. mem `None rs then `None else
590+ if List. mem `False rs then `False else
591+ (* Body was true in every iteration: now reverse-match out-bound
592+ * iteration variables against iteration sources. *)
593+ let ss = List. map (function `True s -> s | _ -> assert false ) rs in
594+ (* Aggregate the out-lists for each out-bound variable. *)
595+ let es_out' =
596+ List. map2 (fun xI eI ->
597+ let tI = match eI.note.it with IterT (tI , _ ) -> tI | _ -> assert false in
598+ let esI = List. map (fun sJ ->
599+ Subst. subst_exp sJ (VarE xI $$ xI.at % tI)
600+ ) ss
601+ in ListE esI $> eI
602+ ) xs_out es_out
603+ in
604+ (* Reverse-match out-bound list values against iteration sources. *)
605+ match match_list match_exp env Subst. empty es_out' es_out with
606+ | Some s' -> `True s'
607+ | None -> `None
608+ else
609+ (* Inconsistent list lengths: can't perform mapping.
610+ * (This is a stuck computation, i.e., undefined.) *)
611+ `None
612+ | ListN _ -> `None
613+ )
505614
506615
507616(* Matching *)
0 commit comments