refactor(builtin): move if_then_else to its own module
Signed-off-by: Leonardo de Moura <leonardo@microsoft.com>
This commit is contained in:
parent
52e11dbbee
commit
2179e57db3
21 changed files with 65 additions and 40 deletions
|
@ -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
|
||||
```
|
||||
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
11
src/builtin/if_then_else.lean
Normal file
11
src/builtin/if_then_else.lean
Normal file
|
@ -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
|
|
@ -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)
|
||||
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
src/builtin/obj/if_then_else.olean
Normal file
BIN
src/builtin/obj/if_then_else.olean
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -260,7 +260,7 @@ expr parser_imp::get_name_ref(name const & id, pos_info const & p, bool implicit
|
|||
std::vector<bool> const & imp_args = get_implicit_arguments(m_env, obj->get_name());
|
||||
buffer<expr> 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());
|
||||
}
|
||||
|
|
|
@ -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<object> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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"));
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import if_then_else
|
||||
set_option lean::parser::verbose false.
|
||||
notation 10 if _ then _ : implies.
|
||||
print environment 1.
|
||||
|
|
|
@ -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 ⊥)
|
||||
|
|
Loading…
Reference in a new issue