Skip to content

Commit 1233422

Browse files
committed
feat: add non-branching boolean operations
1 parent 40e1e09 commit 1233422

File tree

3 files changed

+60
-9
lines changed

3 files changed

+60
-9
lines changed

src/Init/Data/Bool.lean

Lines changed: 48 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,42 @@ public section
1212

1313
namespace Bool
1414

15+
/--
16+
Boolean “logical or”. `lor x y`.
17+
18+
`land x y` is `true` when both of `x` or `y` are `true`. It is functionally the same as
19+
`x && y` but it does not have short-circuiting behavior: any call to `land` will evaluate both
20+
arguments.
21+
22+
Examples:
23+
* `land false false = false`
24+
* `land true false = false`
25+
* `land false true = false`
26+
* `land true true = true`
27+
-/
28+
@[expose, extern "lean_bool_land"]
29+
def land (x y : Bool) : Bool := x && y
30+
31+
@[simp] theorem land_eq_and (x y : Bool) : land x y = (x && y) := rfl
32+
33+
/--
34+
Boolean “logical or”. `lor x y`.
35+
36+
`lor x y` is `true` when at least one of `x` or `y` is `true`. It is functionally the same as
37+
`x || y` but it does not have short-circuiting behavior: any call to `lor` will evaluate both
38+
arguments.
39+
40+
Examples:
41+
* `lor false false = false`
42+
* `lor true false = true`
43+
* `lor false true = true`
44+
* `lor true true = true`
45+
-/
46+
@[expose, extern "lean_bool_lor"]
47+
def lor (x y : Bool) : Bool := x || y
48+
49+
@[simp] theorem lor_eq_or (x y : Bool) : lor x y = (x || y) := rfl
50+
1551
/--
1652
Boolean “exclusive or”. `xor x y` can be written `x ^^ y`.
1753
@@ -25,11 +61,14 @@ Examples:
2561
* `false ^^ true = true`
2662
* `true ^^ true = false`
2763
-/
28-
abbrev xor : Bool → Bool → Bool := bne
64+
@[expose, reducible, extern "lean_bool_xor"]
65+
def xor : Bool → Bool → Bool := bne
66+
67+
@[inherit_doc] infixl:33 " ^^ " => Bool.xor
2968

30-
@[inherit_doc] infixl:33 " ^^ " => xor
69+
recommended_spelling "xor" for "^^" in [Bool.xor, «term_^^_»]
3170

32-
recommended_spelling "xor" for "^^" in [xor, «term_^^_»]
71+
theorem xor_eq_bne (x y : Bool) : (x ^^ y) = (x != y) := rfl
3372

3473
instance (p : Bool → Prop) [inst : DecidablePred p] : Decidable (∀ x, p x) :=
3574
match inst true, inst false with
@@ -48,11 +87,13 @@ instance (p : Bool → Prop) [inst : DecidablePred p] : Decidable (∃ x, p x) :
4887
instance : LE Bool := ⟨(. → .)⟩
4988
instance : LT Bool := ⟨(!. && .)⟩
5089

90+
@[extern "lean_bool_dec_le"]
5191
instance (x y : Bool) : Decidable (x ≤ y) := inferInstanceAs (Decidable (x → y))
92+
@[extern "lean_bool_dec_lt"]
5293
instance (x y : Bool) : Decidable (x < y) := inferInstanceAs (Decidable (!x && y))
5394

54-
instance : Max Bool := ⟨or
55-
instance : Min Bool := ⟨and
95+
instance : Max Bool := ⟨lor
96+
instance : Min Bool := ⟨land
5697

5798
theorem false_ne_true : falsetrue := Bool.noConfusion
5899

@@ -385,7 +426,8 @@ theorem and_or_inj_left_iff :
385426
/--
386427
Converts `true` to `1` and `false` to `0`.
387428
-/
388-
@[expose] def toNat (b : Bool) : Nat := cond b 1 0
429+
@[expose, extern "lean_bool_to_nat"]
430+
def toNat (b : Bool) : Nat := cond b 1 0
389431

390432
@[simp, bitvec_to_nat, grind =] theorem toNat_false : false.toNat = 0 := rfl
391433

src/Init/Prelude.lean

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1006,7 +1006,8 @@ Decides whether two Booleans are equal.
10061006
This function should normally be called via the `DecidableEq Bool` instance that it exists to
10071007
support.
10081008
-/
1009-
@[inline] def Bool.decEq (a b : Bool) : Decidable (Eq a b) :=
1009+
@[extern "lean_bool_dec_eq"]
1010+
def Bool.decEq (a b : Bool) : Decidable (Eq a b) :=
10101011
match a, b with
10111012
| false, false => isTrue rfl
10121013
| false, true => isFalse (fun h => Bool.noConfusion h)
@@ -1177,7 +1178,8 @@ Boolean negation, also known as Boolean complement. `not x` can be written `!x`.
11771178
This is a function that maps the value `true` to `false` and the value `false` to `true`. The
11781179
propositional connective is `Not : Prop → Prop`.
11791180
-/
1180-
@[inline] def Bool.not : Bool → Bool
1181+
@[extern "lean_bool_complement"]
1182+
def Bool.not : Bool → Bool
11811183
| true => false
11821184
| false => true
11831185

src/include/lean/lean.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1780,6 +1780,7 @@ static inline uint8_t lean_int_dec_nonneg(b_lean_obj_arg a) {
17801780

17811781
/* Bool */
17821782

1783+
static inline lean_obj_res lean_bool_to_nat(uint8_t a) { return lean_usize_to_nat((size_t)a); }
17831784
static inline uint8_t lean_bool_to_uint8(uint8_t a) { return a; }
17841785
static inline uint16_t lean_bool_to_uint16(uint8_t a) { return (uint16_t)a; }
17851786
static inline uint32_t lean_bool_to_uint32(uint8_t a) { return (uint32_t)a; }
@@ -1790,7 +1791,13 @@ static inline uint16_t lean_bool_to_int16(uint8_t a) { return (uint16_t)(int16_t
17901791
static inline uint32_t lean_bool_to_int32(uint8_t a) { return (uint32_t)(int32_t)a; }
17911792
static inline uint64_t lean_bool_to_int64(uint8_t a) { return (uint64_t)(int64_t)a; }
17921793
static inline size_t lean_bool_to_isize(uint8_t a) { return (size_t)(ptrdiff_t)a; }
1793-
1794+
static inline uint8_t lean_bool_land(uint8_t a, uint8_t b) { return a & b; }
1795+
static inline uint8_t lean_bool_lor(uint8_t a, uint8_t b) { return a | b; }
1796+
static inline uint8_t lean_bool_xor(uint8_t a, uint8_t b) { return a ^ b; }
1797+
static inline uint8_t lean_bool_complement(uint8_t a) { return a == 0; }
1798+
static inline uint8_t lean_bool_dec_eq(uint8_t a, uint8_t b) { return a == b; }
1799+
static inline uint8_t lean_bool_dec_lt(uint8_t a, uint8_t b) { return a < b; }
1800+
static inline uint8_t lean_bool_dec_le(uint8_t a, uint8_t b) { return a <= b; }
17941801

17951802
/* UInt8 */
17961803

0 commit comments

Comments
 (0)