diff --git a/doc/lean/expr.md b/doc/lean/expr.md index 16f508b891..905353c7ed 100644 --- a/doc/lean/expr.md +++ b/doc/lean/expr.md @@ -35,10 +35,12 @@ eval s + 1 In Lean, the expression `f t` is a function application, where `f` is a function that is applied to `t`. In the following example, we define the function `max`. The `eval` command evaluates the application `max 1 2`, -and returns the value `2`. Note that, the expression `if (x >= y) x y` is also a function application. +and returns the value `2`. Note that, the expression `if (x >= y) then x else y` is also a function application. +It is notation for `ite (x >= y) x y`. ```lean -definition max (x y : Nat) : Nat := if (x >= y) x y +import if_then_else +definition max (x y : Nat) : Nat := if (x >= y) then x else y eval max 1 2 ``` diff --git a/src/builtin/CMakeLists.txt b/src/builtin/CMakeLists.txt index 74edae1893..a8a486f47b 100644 --- a/src/builtin/CMakeLists.txt +++ b/src/builtin/CMakeLists.txt @@ -70,9 +70,8 @@ endfunction() add_kernel_theory("kernel.lean" "${CMAKE_CURRENT_BINARY_DIR}/macros.lua") add_kernel_theory("Nat.lean" "${CMAKE_CURRENT_BINARY_DIR}/kernel.olean") -add_theory("Int.lean" "${CMAKE_CURRENT_BINARY_DIR}/Nat.olean") -add_theory("Real.lean" "${CMAKE_CURRENT_BINARY_DIR}/Int.olean") -add_theory("specialfn.lean" "${CMAKE_CURRENT_BINARY_DIR}/Real.olean") -add_theory("cast.lean" "${CMAKE_CURRENT_BINARY_DIR}/Nat.olean") - - +add_theory("if_then_else.lean" "${CMAKE_CURRENT_BINARY_DIR}/Nat.olean") +add_theory("Int.lean" "${CMAKE_CURRENT_BINARY_DIR}/if_then_else.olean") +add_theory("Real.lean" "${CMAKE_CURRENT_BINARY_DIR}/Int.olean") +add_theory("specialfn.lean" "${CMAKE_CURRENT_BINARY_DIR}/Real.olean") +add_theory("cast.lean" "${CMAKE_CURRENT_BINARY_DIR}/Nat.olean") diff --git a/src/builtin/Int.lean b/src/builtin/Int.lean index 09a4b317fb..7ea445896e 100644 --- a/src/builtin/Int.lean +++ b/src/builtin/Int.lean @@ -1,4 +1,5 @@ import Nat +import if_then_else variable Int : Type alias ℤ : Int @@ -43,7 +44,7 @@ infixl 70 mod : mod definition divides (a b : Int) : Bool := (b mod a) = 0 infix 50 | : divides -definition abs (a : Int) : Int := if (0 ≤ a) a (- a) +definition abs (a : Int) : Int := if (0 ≤ a) then a else (- a) notation 55 | _ | : abs set_opaque sub true diff --git a/src/builtin/Real.lean b/src/builtin/Real.lean index daf8585f67..3fd9c420c6 100644 --- a/src/builtin/Real.lean +++ b/src/builtin/Real.lean @@ -1,4 +1,5 @@ import Int +import if_then_else variable Real : Type alias ℝ : Real @@ -39,6 +40,6 @@ infixl 65 - : sub definition neg (a : Real) : Real := -1.0 * a notation 75 - _ : neg -definition abs (a : Real) : Real := if (0.0 ≤ a) a (- a) +definition abs (a : Real) : Real := if (0.0 ≤ a) then a else (- a) notation 55 | _ | : abs end diff --git a/src/builtin/if_then_else.lean b/src/builtin/if_then_else.lean new file mode 100644 index 0000000000..4f023c92bd --- /dev/null +++ b/src/builtin/if_then_else.lean @@ -0,0 +1,11 @@ +-- if_then_else expression support +builtin ite {A : (Type U)} : Bool → A → A → A +notation 60 if _ then _ else _ : ite + +axiom if_true {A : TypeU} (a b : A) : if true then a else b = a +axiom if_false {A : TypeU} (a b : A) : if false then a else b = b + +theorem if_a_a {A : TypeU} (c : Bool) (a : A) : if c then a else a = a +:= case (λ x, if x then a else a = a) (if_true a a) (if_false a a) c + +set_opaque ite true \ No newline at end of file diff --git a/src/builtin/kernel.lean b/src/builtin/kernel.lean index 62a7ee6c76..35b8db6c8d 100644 --- a/src/builtin/kernel.lean +++ b/src/builtin/kernel.lean @@ -6,7 +6,6 @@ variable Bool : Type -- The following builtin declarations can be removed as soon as Lean supports inductive datatypes and match expressions builtin true : Bool builtin false : Bool -builtin if {A : (Type U)} : Bool → A → A → A definition TypeU := (Type U) diff --git a/src/builtin/obj/Int.olean b/src/builtin/obj/Int.olean index 0f6d1e7a79..09962ad04c 100644 Binary files a/src/builtin/obj/Int.olean and b/src/builtin/obj/Int.olean differ diff --git a/src/builtin/obj/Nat.olean b/src/builtin/obj/Nat.olean index 38c2125bad..afbe1a8d74 100644 Binary files a/src/builtin/obj/Nat.olean and b/src/builtin/obj/Nat.olean differ diff --git a/src/builtin/obj/Real.olean b/src/builtin/obj/Real.olean index 6035111cf1..03fe91b751 100644 Binary files a/src/builtin/obj/Real.olean and b/src/builtin/obj/Real.olean differ diff --git a/src/builtin/obj/if_then_else.olean b/src/builtin/obj/if_then_else.olean new file mode 100644 index 0000000000..dde4ccabbd Binary files /dev/null and b/src/builtin/obj/if_then_else.olean differ diff --git a/src/builtin/obj/kernel.olean b/src/builtin/obj/kernel.olean index af9437bc81..e289798307 100644 Binary files a/src/builtin/obj/kernel.olean and b/src/builtin/obj/kernel.olean differ diff --git a/src/builtin/obj/specialfn.olean b/src/builtin/obj/specialfn.olean index 46af94c193..18ea9a60df 100644 Binary files a/src/builtin/obj/specialfn.olean and b/src/builtin/obj/specialfn.olean differ diff --git a/src/frontends/lean/parser_expr.cpp b/src/frontends/lean/parser_expr.cpp index 4c376c2f4b..2e4d9de771 100644 --- a/src/frontends/lean/parser_expr.cpp +++ b/src/frontends/lean/parser_expr.cpp @@ -260,7 +260,7 @@ expr parser_imp::get_name_ref(name const & id, pos_info const & p, bool implicit std::vector const & imp_args = get_implicit_arguments(m_env, obj->get_name()); buffer args; pos_info p = pos(); - expr f = (k == object_kind::Builtin) ? obj->get_value() : mk_constant(obj->get_name()); + expr f = mk_constant(obj->get_name()); args.push_back(save(f, p)); for (unsigned i = 0; i < imp_args.size(); i++) { if (imp_args[i]) { @@ -270,8 +270,6 @@ expr parser_imp::get_name_ref(name const & id, pos_info const & p, bool implicit } } return mk_app(args); - } else if (k == object_kind::Builtin) { - return obj->get_value(); } else { return mk_constant(obj->get_name()); } diff --git a/src/frontends/lean/pp.cpp b/src/frontends/lean/pp.cpp index f27846cb70..b210c55d1c 100644 --- a/src/frontends/lean/pp.cpp +++ b/src/frontends/lean/pp.cpp @@ -257,6 +257,15 @@ class pp_fn { return ::lean::has_implicit_arguments(m_env, n) && m_local_names.find(n) == m_local_names.end(); } + result pp_value(expr const & e) { + value const & v = to_value(e); + if (has_implicit_arguments(v.get_name())) { + return mk_result(format(get_explicit_version(m_env, v.get_name())), 1); + } else { + return mk_result(v.pp(m_unicode, m_coercion), 1); + } + } + result pp_constant(expr const & e) { name const & n = const_name(e); if (is_placeholder(e)) { @@ -267,16 +276,13 @@ class pp_fn { } else if (has_implicit_arguments(n)) { return mk_result(format(get_explicit_version(m_env, n)), 1); } else { - return mk_result(format(n), 1); - } - } - - result pp_value(expr const & e) { - value const & v = to_value(e); - if (has_implicit_arguments(v.get_name())) { - return mk_result(format(get_explicit_version(m_env, v.get_name())), 1); - } else { - return mk_result(v.pp(m_unicode, m_coercion), 1); + optional obj = m_env->find_object(const_name(e)); + if (obj && obj->is_builtin() && obj->get_name() == const_name(e)) { + // e is a constant that is referencing a builtin object. + return pp_value(obj->get_value()); + } else { + return mk_result(format(n), 1); + } } } diff --git a/src/kernel/builtin.cpp b/src/kernel/builtin.cpp index 3f33cd439d..494edf5a47 100644 --- a/src/kernel/builtin.cpp +++ b/src/kernel/builtin.cpp @@ -80,7 +80,7 @@ bool is_false(expr const & e) { // ======================================= // If-then-else builtin operator -static name g_if_name("if"); +static name g_if_name("ite"); static format g_if_fmt(g_if_name); /** \brief Semantic attachment for if-then-else operator with type @@ -108,12 +108,12 @@ public: return none_expr(); } } - virtual void write(serializer & s) const { s << "if"; } + virtual void write(serializer & s) const { s << "ite"; } }; MK_BUILTIN(if_fn, if_fn_value); MK_IS_BUILTIN(is_if_fn, mk_if_fn()); -static register_builtin_fn if_blt("if", []() { return mk_if_fn(); }); -static value::register_deserializer_fn if_ds("if", [](deserializer & ) { return mk_if_fn(); }); +static register_builtin_fn if_blt("ite", []() { return mk_if_fn(); }); +static value::register_deserializer_fn if_ds("ite", [](deserializer & ) { return mk_if_fn(); }); // ======================================= MK_CONSTANT(implies_fn, name("implies")); diff --git a/src/library/elaborator/elaborator.cpp b/src/library/elaborator/elaborator.cpp index 24e6a07cdc..4d414cc803 100644 --- a/src/library/elaborator/elaborator.cpp +++ b/src/library/elaborator/elaborator.cpp @@ -1342,13 +1342,11 @@ class elaborator::imp { if (a == b) return true; if (!has_metavar(a) && !has_metavar(b)) { - if (!eq) { - if (m_type_inferer.is_convertible(a, b, ctx)) { - return true; - } else { - m_conflict = mk_failure_justification(c); - return false; - } + if (m_type_inferer.is_convertible(a, b, ctx)) { + return true; + } else { + m_conflict = mk_failure_justification(c); + return false; } } diff --git a/tests/lean/arith7.lean.expected.out b/tests/lean/arith7.lean.expected.out index 8eccc5aefc..2d1171ec3b 100644 --- a/tests/lean/arith7.lean.expected.out +++ b/tests/lean/arith7.lean.expected.out @@ -7,7 +7,7 @@ 2 ⊤ Assumed: y -if (0 ≤ -3 + y) (-3 + y) (-1 * (-3 + y)) +if (0 ≤ -3 + y) then -3 + y else -1 * (-3 + y) | x + y | > x Set: lean::pp::notation Int::gt (Int::abs (Int::add x y)) x diff --git a/tests/lean/tst1.lean b/tests/lean/tst1.lean index b872329ff7..86eb585451 100644 --- a/tests/lean/tst1.lean +++ b/tests/lean/tst1.lean @@ -1,3 +1,4 @@ +import if_then_else -- Define a "fake" type to simulate the natural numbers. This is just a test. variable N : Type variable lt : N -> N -> Bool @@ -9,7 +10,7 @@ infix 50 < : lt axiom two_lt_three : two < three definition vector (A : Type) (n : N) : Type := forall (i : N) (H : i < n), A definition const {A : Type} (n : N) (d : A) : vector A n := fun (i : N) (H : i < n), d -definition update {A : Type} {n : N} (v : vector A n) (i : N) (d : A) : vector A n := fun (j : N) (H : j < n), if (j = i) d (v j H) +definition update {A : Type} {n : N} (v : vector A n) (i : N) (d : A) : vector A n := fun (j : N) (H : j < n), if (j = i) then d else (v j H) definition select {A : Type} {n : N} (v : vector A n) (i : N) (H : i < n) : A := v i H definition map {A B C : Type} {n : N} (f : A -> B -> C) (v1 : vector A n) (v2 : vector B n) : vector C n := fun (i : N) (H : i < n), f (v1 i H) (v2 i H) print environment 10 diff --git a/tests/lean/tst1.lean.expected.out b/tests/lean/tst1.lean.expected.out index f3d47c176d..3a2e3c11f4 100644 --- a/tests/lean/tst1.lean.expected.out +++ b/tests/lean/tst1.lean.expected.out @@ -1,5 +1,6 @@ Set: pp::colors Set: pp::unicode + Imported 'if_then_else' Assumed: N Assumed: lt Assumed: zero @@ -20,12 +21,12 @@ axiom two_lt_three : two < three definition vector (A : Type) (n : N) : Type := ∀ (i : N), i < n → A definition const {A : Type} (n : N) (d : A) : vector A n := λ (i : N) (H : i < n), d definition update {A : Type} {n : N} (v : vector A n) (i : N) (d : A) : vector A n := - λ (j : N) (H : j < n), if (j = i) d (v j H) + λ (j : N) (H : j < n), if (j = i) then d else v j H definition select {A : Type} {n : N} (v : vector A n) (i : N) (H : i < n) : A := v i H definition map {A B C : Type} {n : N} (f : A → B → C) (v1 : vector A n) (v2 : vector B n) : vector C n := λ (i : N) (H : i < n), f (v1 i H) (v2 i H) select (update (const three ⊥) two ⊤) two two_lt_three : Bool -if (two == two) ⊤ ⊥ +if (two == two) then ⊤ else ⊥ update (const three ⊥) two ⊤ : vector Bool three -------- @@ -45,4 +46,4 @@ map normal form --> f (v1 i H) (v2 i H) update normal form --> -λ (A : Type) (n : N) (v : ∀ (i : N), i < n → A) (i : N) (d : A) (j : N) (H : j < n), if (j == i) d (v j H) +λ (A : Type) (n : N) (v : ∀ (i : N), i < n → A) (i : N) (d : A) (j : N) (H : j < n), if (j == i) then d else v j H diff --git a/tests/lean/tst3.lean b/tests/lean/tst3.lean index c2bd48ba5e..c60b7acc26 100644 --- a/tests/lean/tst3.lean +++ b/tests/lean/tst3.lean @@ -1,3 +1,4 @@ +import if_then_else set_option lean::parser::verbose false. notation 10 if _ then _ : implies. print environment 1. diff --git a/tests/lean/tst3.lean.expected.out b/tests/lean/tst3.lean.expected.out index c51f19fa0a..d4f95ad91d 100644 --- a/tests/lean/tst3.lean.expected.out +++ b/tests/lean/tst3.lean.expected.out @@ -1,5 +1,12 @@ Set: pp::colors Set: pp::unicode + Imported 'if_then_else' +Notation has been redefined, the existing notation: + notation 60 if _ then _ else _ +has been replaced with: + notation 10 if _ then _ +because they conflict with each other. +The precedence of 'then' changed from 60 to 10. notation 10 if _ then _ : implies if ⊤ then ⊥ if ⊤ then (if a then ⊥)