Section BR.
Inductive BR :=
| mkBR : R -> (R -> R -> R) -> (nat -> R) -> BR.
(** I need to define the notation outside again as wel **)
Notation "'{{' const ',' bop ',' fn  '}}'" :=
(mkBR const bop fn) (at level 30).
(** Semantics of evaluating a BR. It's too convenient to be able to `Opaque` and `Transparent` this to give it up *)
Definition evalBR (br: BR) (n: nat): R :=
match br with
| mkBR r0 binop f =>
let
vals : list R := map f (seq 1 n)
in
fold_left binop vals r0
end.
(** semantics of evaluating a BR *)
Global Instance loopVariantBR : LoopVariant BR R :=
{
evalAtIx (br: BR) (n: nat) := evalBR br n
}.
Class ToBR A : Type  :=
{
toBR : A -> BR
}.
Global Instance liftConstantToBR : ToBR R :=
{
toBR (c: R) := mkBR c plus (const zero)
}.
Global Instance liftBRToBR: ToBR BR :=
{
toBR br := br
}.
Hint Resolve liftConstant_eval : Recurrence.
Hint Rewrite liftConstant_eval : Recurrence.

(** Most basic theorem, show how to unfold BR execution *)
Lemma evalBR_step: forall `{Ring R} (r0: R) (bop: R -> R -> R) (f: nat -> R) (n : nat),
({{r0, bop, f}}) # (S n) = bop ((mkBR r0 bop f) # n)  (f # (S n)).