import Base
import Nat
union UInt {
bzero
dub_inc(UInt)
inc_dub(UInt)
}
recursive toNat(UInt) -> Nat {
toNat(bzero) = ℕ0
toNat(dub_inc(x)) = ℕ2 * suc(toNat(x))
toNat(inc_dub(x)) = suc(ℕ2 * toNat(x))
}
assert toNat(bzero) = ℕ0
assert toNat(inc_dub(bzero)) = ℕ1
assert toNat(dub_inc(bzero)) = ℕ2
assert toNat(inc_dub(inc_dub(bzero))) = ℕ3
assert toNat(dub_inc(inc_dub(bzero))) = ℕ4
recursive operator< (UInt, UInt) -> bool {
operator < (bzero, y) =
switch y {
case bzero { false }
case dub_inc(y') { true }
case inc_dub(y') { true }
}
operator < (dub_inc(x'), y) =
switch y {
case bzero { false }
case dub_inc(y') { x' < y' }
case inc_dub(y') { x' < y' }
}
operator < (inc_dub(x'), y) =
switch y {
case bzero { false }
case dub_inc(y') { x' < y' or x' = y' }
case inc_dub(y') { x' < y' }
}
}
fun operator ≤ (x:UInt, y:UInt) {
x < y or x = y
}
fun operator > (x:UInt, y:UInt) {
y < x
}
fun operator ≥ (x:UInt, y:UInt) {
y ≤ x
}
recursive dub(UInt) -> UInt {
dub(bzero) = bzero
dub(dub_inc(x)) = dub_inc(inc_dub(x))
dub(inc_dub(x)) = dub_inc(dub(x))
}
recursive inc(UInt) -> UInt {
inc(bzero) = inc_dub(bzero)
inc(dub_inc(x)) = inc_dub(inc(x))
inc(inc_dub(x)) = dub_inc(x)
}
fun pred(x:UInt) {
switch x {
case bzero { bzero }
case dub_inc(x') { inc_dub(x') }
case inc_dub(x') { dub(x') }
}
}
recursive operator+(UInt, UInt) -> UInt {
operator+(bzero, y) = y
operator+(dub_inc(x), y) =
switch y {
case bzero { dub_inc(x) }
case dub_inc(y') { dub_inc(inc(x + y')) }
case inc_dub(y') { inc(dub_inc(x + y')) }
}
operator+(inc_dub(x), y) =
switch y {
case bzero { inc_dub(x) }
case dub_inc(y') { inc(dub_inc(x + y')) }
case inc_dub(y') { inc(inc_dub(x + y')) }
}
}
recursive operator ∸ (UInt, UInt) -> UInt {
operator∸(bzero, y) = bzero
operator∸(dub_inc(x), y) =
switch y {
case bzero { dub_inc(x) }
case dub_inc(y') { dub(x ∸ y') }
case inc_dub(y') {
if x < y' then bzero
else inc_dub(x ∸ y')
}
}
operator∸(inc_dub(x), y) =
switch y {
case bzero { inc_dub(x) }
case dub_inc(y') {
if x < y' then bzero else pred(dub(x ∸ y'))
}
case inc_dub(y') { dub(x ∸ y') }
}
}
recursive operator *(UInt, UInt) -> UInt {
operator*(bzero, y) = bzero
operator*(dub_inc(x), y) =
switch y {
case bzero { bzero }
case dub_inc(y') {
dub(dub_inc(x + y' + x * y'))
}
case inc_dub(y') {
dub_inc(x + dub(y' + x*y'))
}
}
operator*(inc_dub(x), y) =
switch y {
case bzero { bzero }
case dub_inc(y') {
dub_inc(dub(x) + y' + dub(x * y'))
}
case inc_dub(y') {
inc_dub(x + y' + dub(x * y'))
}
}
}
fun sqr(a : UInt) { a * a }
recursive expt(UInt, UInt) -> UInt {
expt(bzero, a) = inc_dub(bzero)
expt(dub_inc(p), a) = sqr(a * expt(p, a))
expt(inc_dub(p), a) = a * sqr(expt(p, a))
}
fun operator ^(a : UInt, b : UInt) {
expt(b, a)
}
recursive fromNat(Nat) -> UInt {
fromNat(0) = bzero
fromNat(suc(n)) = inc(fromNat(n))
}
fun max(x : UInt, y : UInt) {
if x < y then y
else x
}
fun min(x : UInt, y : UInt) {
if x < y then x
else y
}