refactor(builtin): move if_then_else to its own module

Signed-off-by: Leonardo de Moura <leonardo@microsoft.com>
This commit is contained in:
Leonardo de Moura 2014-01-09 14:06:23 -08:00
parent 52e11dbbee
commit 2179e57db3
21 changed files with 65 additions and 40 deletions

View file

@ -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
```

View file

@ -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")

View file

@ -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

View file

@ -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

View 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

View file

@ -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.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -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());
}

View file

@ -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);
}
}
}

View file

@ -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"));

View file

@ -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;
}
}

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -1,3 +1,4 @@
import if_then_else
set_option lean::parser::verbose false.
notation 10 if _ then _ : implies.
print environment 1.

View file

@ -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 ⊥)