@@ -474,34 +474,144 @@ 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+ (* Iterationen values es_in are in hnf, so got to be options. *)
528+ let eos_in = List. map as_opt_exp es_in in
529+ if List. for_all Option. is_none eos_in then
530+ (* Iterating over empty options: nothing to do. *)
531+ `True Subst. empty
532+ else if List. for_all Option. is_some eos_in then
533+ (* All iteration variables are non-empty: reduce body. *)
534+ let es1_in = List. map Option. get eos_in in
535+ (* s substitutes in-bound iteration variables with corresponding
536+ * values. *)
537+ let s = List. fold_left2 Subst. add_varid Subst. empty xs_in es1_in in
538+ match reduce_prem env (Subst. subst_prem s prem1) with
539+ | (`None | `False ) as r -> r
540+ | `True s' ->
541+ (* Body is true: now reverse-match out-bound iteration values
542+ * against iteration sources. *)
543+ match
544+ List. fold_left (fun s_opt (xI , eI ) ->
545+ let * s = s_opt in
546+ let tI = match eI.note.it with IterT (tI , _ ) -> tI | _ -> assert false in
547+ match_exp' env s (OptE (Some (Subst. subst_exp s' (VarE xI $$ xI.at % tI))) $> eI) eI
548+ ) (Some Subst. empty) xes_out
549+ with
550+ | Some s'' -> `True s''
551+ | None -> `None
552+ else
553+ (* Inconsistent arity of iteration values: can't perform mapping.
554+ * (This is a stuck computation, i.e., undefined.) *)
555+ `None
556+ | List | List1 ->
557+ (* Unspecified iteration count: get length from (first) iteration value
558+ * and start over; es_in are in hnf, so got to be lists. *)
559+ let n = List. length (as_list_exp (List. hd es_in)) in
560+ if iter' = List || n > = 1 then
561+ let en = NumE (`Nat (Z. of_int n)) $$ prem.at % (NumT `NatT $ prem.at) in
562+ reduce_prem env (IterPr (prem1, (ListN (en, None ), xes')) $> prem)
563+ else
564+ (* List is empty although it is List1: inconsistency.
565+ * (This is a stuck computation, i.e., undefined.) *)
566+ `None
567+ | ListN ({it = NumE (`Nat n' ); _} , xo ) ->
568+ (* Iterationen values es_in are in hnf, so got to be lists. *)
569+ let ess_in = List. map as_list_exp es_in in
570+ let ns = List. map List. length ess_in in
571+ let n = Z. to_int n' in
572+ if List. for_all ((= ) n) ns then
573+ (* All in-bound lists have the expected length: reduce body,
574+ * once for each tuple of values from the iterated lists. *)
575+ let rs = List. init n (fun i ->
576+ let esI_in = List. map (fun es -> List. nth es i) ess_in in
577+ (* s substitutes in-bound iteration variables with corresponding
578+ * values for this respective iteration. *)
579+ let s = List. fold_left2 Subst. add_varid Subst. empty xs_in esI_in in
580+ (* Add iteration counter variable if used. *)
581+ let s' =
582+ Option. fold xo ~none: s ~some: (fun x ->
583+ let en = NumE (`Nat (Z. of_int i)) $$ x.at % (NumT `NatT $ x.at) in
584+ Subst. add_varid s x en
585+ )
586+ in
587+ reduce_prem env (Subst. subst_prem s' prem1)
588+ )
589+ in
590+ if List. mem `None rs then `None else
591+ if List. mem `False rs then `False else
592+ (* Body was true in every iteration: now reverse-match out-bound
593+ * iteration variables against iteration sources. *)
594+ let ss = List. map (function `True s -> s | _ -> assert false ) rs in
595+ (* Aggregate the out-lists for each out-bound variable. *)
596+ let es_out' =
597+ List. map2 (fun xI eI ->
598+ let tI = match eI.note.it with IterT (tI , _ ) -> tI | _ -> assert false in
599+ let esI = List. map (fun sJ ->
600+ Subst. subst_exp sJ (VarE xI $$ xI.at % tI)
601+ ) ss
602+ in ListE esI $> eI
603+ ) xs_out es_out
604+ in
605+ (* Reverse-match out-bound list values against iteration sources. *)
606+ match match_list match_exp env Subst. empty es_out' es_out with
607+ | Some s' -> `True s'
608+ | None -> `None
609+ else
610+ (* Inconsistent list lengths: can't perform mapping.
611+ * (This is a stuck computation, i.e., undefined.) *)
612+ `None
613+ | ListN _ -> `None
614+ )
505615
506616
507617(* Matching *)
0 commit comments