First, a few helper operators:
Pick(S) == CHOOSE s \in S : TRUE
RECURSIVE SetReduce(_, _, _)
SetReduce(Op(_, _), S, value) == IF S = {} THEN value
ELSE LET s == Pick(S)
IN SetReduce(Op, S \ {s}, Op(s, value))
Note that SetReduce
only works for commutative operators. You will have to define a separate operator if you want to reduce over a function.
If you’re concerned about accidentally passing in a noncommutative operator, we can make a ‘safe’ reduce that fails iff any given step is not commutative.
EXTENDS TLC
SetReduce(Op(_, _), S, value) ==
IF S = {} THEN value
ELSE LET s == Pick(S)
IN IF Op(s, value) = Op(value, s)
THEN SetReduce(Op, S \ {s}, Op(s, value))
ELSE Assert(FALSE, "oh no")
Sum(S) == LET _op(a, b) == a + b
IN SetReduce(_op, S, 0)
Two different ways to do it.
Max(S) == CHOOSE x \in S:
\A y \in S:
y <= x
Min(S) == CHOOSE x \in S:
\A y \in S \ {x}:
y > x