Add natural numbers. Fix how coercions and overloads interact (switch to approach used in C++). Add notation for natural and integer arithmetic. Rename m and u universe variables to M and U.

Signed-off-by: Leonardo de Moura <leonardo@microsoft.com>
This commit is contained in:
Leonardo de Moura 2013-09-02 12:24:29 -07:00
parent 7acf438bf4
commit 0a67679afb
18 changed files with 384 additions and 129 deletions

View file

@ -201,42 +201,50 @@ class elaborator::imp {
buffer<unsigned> good_choices;
unsigned num_choices = f_choices.size();
unsigned num_args = args.size();
for (unsigned j = 0; j < num_choices; j++) {
expr f_t = f_choice_types[j];
try {
unsigned i = 1;
for (; i < num_args; i++) {
f_t = check_pi(f_t, ctx, src, ctx);
expr expected = abst_domain(f_t);
expr given = types[i];
if (!has_metavar(expected) && !has_metavar(given)) {
if (!is_convertible(expected, given, ctx) &&
!m_frontend.get_coercion(given, expected))
break; // failed to use this overload
for (unsigned round = 0; round < 2; round++) {
// In the first round we only select perfect matches without considering
// overloads. This is the same approach used in C++.
// If a perfect match does not exist, then we try again using coercions.
for (unsigned j = 0; j < num_choices; j++) {
expr f_t = f_choice_types[j];
try {
unsigned i = 1;
for (; i < num_args; i++) {
f_t = check_pi(f_t, ctx, src, ctx);
expr expected = abst_domain(f_t);
expr given = types[i];
if (!has_metavar(expected) && !has_metavar(given)) {
if (!is_convertible(expected, given, ctx) &&
// remark, we only consider coercions in the second round
(round == 0 || !m_frontend.get_coercion(given, expected)))
break; // failed to use this overload
}
f_t = instantiate_free_var_mmv(abst_body(f_t), 0, args[i]);
}
f_t = instantiate_free_var_mmv(abst_body(f_t), 0, args[i]);
}
if (i == num_args) {
if (good_choices.empty()) {
// first good choice
args[0] = f_choices[j];
types[0] = f_choice_types[j];
if (i == num_args) {
if (good_choices.empty()) {
// first good choice
args[0] = f_choices[j];
types[0] = f_choice_types[j];
}
good_choices.push_back(j);
}
good_choices.push_back(j);
} catch (exception & ex) {
// candidate failed
// do nothing
}
} catch (exception & ex) {
// candidate failed
// do nothing
}
}
if (good_choices.size() == 0) {
// TODO add information to the exception
throw exception("none of the overloads are good");
} else if (good_choices.size() == 1) {
// found overload
} else {
// TODO add information to the exception
throw exception("ambiguous overload");
if (good_choices.size() == 0) {
// TODO add information to the exception
if (round == 1)
throw exception("none of the overloads are good");
} else if (good_choices.size() == 1) {
// found overload
return;
} else {
// TODO add information to the exception
throw exception("ambiguous overload");
}
}
}

View file

@ -7,6 +7,7 @@ Author: Leonardo de Moura
#include "builtin.h"
#include "basic_thms.h"
#include "lean_frontend.h"
#include "arith.h"
namespace lean {
/**
@ -29,6 +30,28 @@ void init_builtin_notation(frontend & f) {
f.add_infixr("<=>", 25, mk_iff_fn()); // "<=>"
f.add_infixr("\u21D4", 25, mk_iff_fn()); // "⇔"
f.add_infixl("+", 65, mk_nat_add_fn());
f.add_infixl("*", 70, mk_nat_mul_fn());
f.add_infix("<=", 50, mk_nat_le_fn());
f.add_infix("\u2264", 50, mk_nat_le_fn()); // ≤
f.add_infix(">=", 50, mk_nat_ge_fn());
f.add_infix("\u2265", 50, mk_nat_ge_fn()); // ≥
f.add_infix("<", 50, mk_nat_lt_fn());
f.add_infix(">", 50, mk_nat_gt_fn());
f.add_infixl("+", 65, mk_int_add_fn());
f.add_infixl("-", 65, mk_int_sub_fn());
f.add_infixl("*", 70, mk_int_mul_fn());
f.add_infixl("/", 70, mk_int_div_fn());
f.add_infix("<=", 50, mk_int_le_fn());
f.add_infix("\u2264", 50, mk_int_le_fn()); // ≤
f.add_infix(">=", 50, mk_int_ge_fn());
f.add_infix("\u2265", 50, mk_int_ge_fn()); // ≥
f.add_infix("<", 50, mk_int_lt_fn());
f.add_infix(">", 50, mk_int_gt_fn());
f.add_coercion(mk_nat_to_int_fn());
// implicit arguments for builtin axioms
f.mark_implicit_arguments(mk_mp_fn(), {true, true, false, false});
f.mark_implicit_arguments(mk_discharge_fn(), {true, true, false});

View file

@ -199,8 +199,8 @@ class parser::imp {
bool curr_is_identifier() const { return curr() == scanner::token::Id; }
/** \brief Return true iff the current token is a '_" */
bool curr_is_placeholder() const { return curr() == scanner::token::Placeholder; }
/** \brief Return true iff the current token is an integer */
bool curr_is_int() const { return curr() == scanner::token::IntVal; }
/** \brief Return true iff the current token is a natural number */
bool curr_is_nat() const { return curr() == scanner::token::NatVal; }
/** \brief Return true iff the current token is a '(' */
bool curr_is_lparen() const { return curr() == scanner::token::LeftParen; }
/** \brief Return true iff the current token is a '{' */
@ -254,10 +254,11 @@ class parser::imp {
m_builtins["\u22A4"] = True;
m_builtins["\u22A5"] = False;
m_builtins["Int"] = Int;
m_builtins["Nat"] = Nat;
}
unsigned parse_unsigned(char const * msg) {
lean_assert(curr_is_int());
lean_assert(curr_is_nat());
mpz pval = curr_num().get_numerator();
if (!pval.is_unsigned_int()) {
throw parser_error(msg, pos());
@ -285,7 +286,7 @@ class parser::imp {
auto p = pos();
next();
buffer<level> lvls;
while (curr_is_identifier() || curr_is_int()) {
while (curr_is_identifier() || curr_is_nat()) {
lvls.push_back(parse_level());
}
if (lvls.size() < 2)
@ -318,7 +319,7 @@ class parser::imp {
level parse_level_nud() {
switch (curr()) {
case scanner::token::Id: return parse_level_nud_id();
case scanner::token::IntVal: return parse_level_nud_int();
case scanner::token::NatVal: return parse_level_nud_int();
default:
throw parser_error("invalid level expression", pos());
}
@ -853,10 +854,10 @@ class parser::imp {
}
}
/** \brief Parse an integer value. */
expr parse_int() {
/** \brief Parse a natural number value. */
expr parse_nat() {
auto p = pos();
expr r = save(mk_int_value(m_scanner.get_num_val().get_numerator()), p);
expr r = save(mk_nat_value(m_scanner.get_num_val().get_numerator()), p);
next();
return r;
}
@ -873,7 +874,7 @@ class parser::imp {
expr parse_type() {
auto p = pos();
next();
if (curr_is_identifier() || curr_is_int()) {
if (curr_is_identifier() || curr_is_nat()) {
return save(mk_type(parse_level()), p);
} else {
return Type();
@ -899,7 +900,7 @@ class parser::imp {
case scanner::token::Forall: return parse_forall();
case scanner::token::Exists: return parse_exists();
case scanner::token::Let: return parse_let();
case scanner::token::IntVal: return parse_int();
case scanner::token::NatVal: return parse_nat();
case scanner::token::DecimalVal: return parse_decimal();
case scanner::token::StringVal: return parse_string();
case scanner::token::Placeholder: return parse_placeholder();
@ -927,7 +928,7 @@ class parser::imp {
case scanner::token::Eq: return parse_eq(left);
case scanner::token::Arrow: return parse_arrow(left);
case scanner::token::LeftParen: return mk_app_left(left, parse_lparen());
case scanner::token::IntVal: return mk_app_left(left, parse_int());
case scanner::token::NatVal: return mk_app_left(left, parse_nat());
case scanner::token::DecimalVal: return mk_app_left(left, parse_decimal());
case scanner::token::StringVal: return mk_app_left(left, parse_string());
case scanner::token::Placeholder: return mk_app_left(left, parse_placeholder());
@ -954,7 +955,7 @@ class parser::imp {
}
case scanner::token::Eq : return g_eq_precedence;
case scanner::token::Arrow : return g_arrow_precedence;
case scanner::token::LeftParen: case scanner::token::IntVal: case scanner::token::DecimalVal:
case scanner::token::LeftParen: case scanner::token::NatVal: case scanner::token::DecimalVal:
case scanner::token::StringVal: case scanner::token::Type: case scanner::token::Placeholder:
return 1;
default:
@ -1119,7 +1120,7 @@ class parser::imp {
name opt_id = curr_name();
next();
if (opt_id == g_env_kwd) {
if (curr_is_int()) {
if (curr_is_nat()) {
unsigned i = parse_unsigned("invalid argument, value does not fit in a machine integer");
auto end = m_frontend.end_objects();
auto beg = m_frontend.begin_objects();
@ -1155,7 +1156,7 @@ class parser::imp {
/** \brief Return the (optional) precedence of a user-defined operator. */
unsigned parse_precedence() {
if (curr_is_int()) {
if (curr_is_nat()) {
return parse_unsigned("invalid operator definition, precedence does not fit in a machine integer");
} else {
return 0;
@ -1296,7 +1297,7 @@ class parser::imp {
m_frontend.set_option(id, curr_string());
next();
break;
case scanner::token::IntVal:
case scanner::token::NatVal:
if (k != IntOption && k != UnsignedOption)
throw parser_error("invalid option value, given option is not an integer", pos());
m_frontend.set_option(id, parse_unsigned("invalid option value, value does not fit in a machine integer"));
@ -1450,7 +1451,7 @@ class parser::imp {
}
public:
imp(frontend & fe, std::istream & in, bool use_exceptions, bool interactive):
imp(frontend const & fe, std::istream & in, bool use_exceptions, bool interactive):
m_frontend(fe),
m_scanner(in),
m_elaborator(fe),
@ -1543,7 +1544,7 @@ public:
}
};
parser::parser(frontend fe, std::istream & in, bool use_exceptions, bool interactive) {
parser::parser(frontend const & fe, std::istream & in, bool use_exceptions, bool interactive) {
parser::imp::show_prompt(interactive, fe);
m_ptr.reset(new imp(fe, in, use_exceptions, interactive));
}
@ -1563,7 +1564,7 @@ expr parser::parse_expr() {
return m_ptr->parse_expr_main();
}
shell::shell(frontend & fe):m_frontend(fe) {
shell::shell(frontend const & fe):m_frontend(fe) {
}
shell::~shell() {

View file

@ -15,7 +15,7 @@ class parser {
class imp;
std::unique_ptr<imp> m_ptr;
public:
parser(frontend fe, std::istream & in, bool use_exceptions = true, bool interactive = false);
parser(frontend const & fe, std::istream & in, bool use_exceptions = true, bool interactive = false);
~parser();
/** \brief Parse a sequence of commands */
@ -34,7 +34,7 @@ class shell {
frontend m_frontend;
interruptable_ptr<parser> m_parser;
public:
shell(frontend & fe);
shell(frontend const & fe);
~shell();
bool operator()();

View file

@ -302,7 +302,7 @@ scanner::token scanner::read_number() {
}
if (is_decimal)
m_num_val /= q;
return is_decimal ? token::DecimalVal : token::IntVal;
return is_decimal ? token::DecimalVal : token::NatVal;
}
scanner::token scanner::read_string() {
@ -389,7 +389,7 @@ std::ostream & operator<<(std::ostream & out, scanner::token const & t) {
case scanner::token::In: out << "in"; break;
case scanner::token::Id: out << "Id"; break;
case scanner::token::CommandId: out << "CId"; break;
case scanner::token::IntVal: out << "Int"; break;
case scanner::token::NatVal: out << "Nat"; break;
case scanner::token::DecimalVal: out << "Dec"; break;
case scanner::token::StringVal: out << "String"; break;
case scanner::token::Eq: out << "="; break;

View file

@ -19,7 +19,7 @@ class scanner {
public:
enum class token {
LeftParen, RightParen, LeftCurlyBracket, RightCurlyBracket, Colon, Comma, Period, Lambda, Pi, Arrow,
Let, In, Forall, Exists, Id, CommandId, IntVal, DecimalVal, StringVal, Eq, Assign, Type, Placeholder, Eof
Let, In, Forall, Exists, Id, CommandId, NatVal, DecimalVal, StringVal, Eq, Assign, Type, Placeholder, Eof
};
protected:
int m_spos; // position in the current line of the stream

View file

@ -10,16 +10,130 @@ Author: Leonardo de Moura
#include "environment.h"
namespace lean {
class int_type_value : public value {
/** \brief Base class for Nat, Int and Real types */
class num_type_value : public value {
name m_name;
public:
virtual ~int_type_value() {}
num_type_value(char const * name):m_name(name) {}
virtual ~num_type_value() {}
virtual expr get_type() const { return Type(); }
virtual bool normalize(unsigned num_args, expr const * args, expr & r) const { return false; }
virtual void display(std::ostream & out) const { out << m_name; }
virtual format pp() const { return format(m_name); }
virtual unsigned hash() const { return m_name.hash(); }
};
// =======================================
// Natural numbers
class nat_type_value : public num_type_value {
public:
nat_type_value():num_type_value("Nat") {}
virtual bool operator==(value const & other) const { return dynamic_cast<nat_type_value const*>(&other) != nullptr; }
};
expr const Nat = mk_value(*(new nat_type_value()));
expr mk_nat_type() { return Nat; }
class nat_value_value : public value {
mpz m_val;
public:
nat_value_value(mpz const & v):m_val(v) { lean_assert(v >= 0); }
virtual ~nat_value_value() {}
virtual expr get_type() const { return Nat; }
virtual bool normalize(unsigned num_args, expr const * args, expr & r) const { return false; }
virtual bool operator==(value const & other) const {
nat_value_value const * _other = dynamic_cast<nat_value_value const*>(&other);
return _other && _other->m_val == m_val;
}
virtual void display(std::ostream & out) const { out << m_val; }
virtual format pp() const { return format(m_val); }
virtual unsigned hash() const { return m_val.hash(); }
mpz const & get_num() const { return m_val; }
};
expr mk_nat_value(mpz const & v) {
return mk_value(*(new nat_value_value(v)));
}
bool is_nat_value(expr const & e) {
return is_value(e) && dynamic_cast<nat_value_value const *>(&to_value(e)) != nullptr;
}
mpz const & nat_value_numeral(expr const & e) {
lean_assert(is_nat_value(e));
return static_cast<nat_value_value const &>(to_value(e)).get_num();
}
template<char const * Name, typename F>
class nat_bin_op : public value {
expr m_type;
name m_name;
public:
nat_bin_op() {
m_type = Nat >> (Nat >> Nat);
m_name = name("Nat", Name);
}
virtual ~nat_bin_op() {}
virtual expr get_type() const { return m_type; }
virtual bool operator==(value const & other) const { return dynamic_cast<nat_bin_op const*>(&other) != nullptr; }
virtual bool normalize(unsigned num_args, expr const * args, expr & r) const {
if (num_args == 3 && is_nat_value(args[1]) && is_nat_value(args[2])) {
r = mk_nat_value(F()(nat_value_numeral(args[1]), nat_value_numeral(args[2])));
return true;
} else {
return false;
}
}
virtual void display(std::ostream & out) const { out << m_name; }
virtual format pp() const { return format(m_name); }
virtual unsigned hash() const { return m_name.hash(); }
};
constexpr char nat_add_name[] = "add";
struct nat_add_eval { mpz operator()(mpz const & v1, mpz const & v2) { return v1 + v2; }; };
typedef nat_bin_op<nat_add_name, nat_add_eval> nat_add_value;
MK_BUILTIN(nat_add_fn, nat_add_value);
constexpr char nat_mul_name[] = "mul";
struct nat_mul_eval { mpz operator()(mpz const & v1, mpz const & v2) { return v1 * v2; }; };
typedef nat_bin_op<nat_mul_name, nat_mul_eval> nat_mul_value;
MK_BUILTIN(nat_mul_fn, nat_mul_value);
class nat_le_value : public value {
expr m_type;
name m_name;
public:
nat_le_value() {
m_type = Nat >> (Nat >> Bool);
m_name = name{"Nat", "le"};
}
virtual ~nat_le_value() {}
virtual expr get_type() const { return m_type; }
virtual bool operator==(value const & other) const { return dynamic_cast<nat_le_value const*>(&other) != nullptr; }
virtual bool normalize(unsigned num_args, expr const * args, expr & r) const {
if (num_args == 3 && is_nat_value(args[1]) && is_nat_value(args[2])) {
r = mk_bool_value(nat_value_numeral(args[1]) <= nat_value_numeral(args[2]));
return true;
} else {
return false;
}
}
virtual void display(std::ostream & out) const { out << m_name; }
virtual format pp() const { return format(m_name); }
virtual unsigned hash() const { return m_name.hash(); }
};
MK_BUILTIN(nat_le_fn, nat_le_value);
MK_CONSTANT(nat_ge_fn, name(name("Nat"), "ge"));
MK_CONSTANT(nat_lt_fn, name(name("Nat"), "lt"));
MK_CONSTANT(nat_gt_fn, name(name("Nat"), "gt"));
// =======================================
// =======================================
// Integers
class int_type_value : public num_type_value {
public:
int_type_value():num_type_value("Int") {}
virtual bool operator==(value const & other) const { return dynamic_cast<int_type_value const*>(&other) != nullptr; }
virtual void display(std::ostream & out) const { out << "Int"; }
virtual format pp() const { return format("Int"); }
virtual unsigned hash() const { return 41; }
};
expr const Int = mk_value(*(new int_type_value()));
expr mk_int_type() { return Int; }
@ -54,12 +168,14 @@ mpz const & int_value_numeral(expr const & e) {
return static_cast<int_value_value const &>(to_value(e)).get_num();
}
template<char const * Name, unsigned Hash, typename F>
template<char const * Name, typename F>
class int_bin_op : public value {
expr m_type;
expr m_type;
name m_name;
public:
int_bin_op() {
m_type = Int >> (Int >> Int);
m_name = name("Int", Name);
}
virtual ~int_bin_op() {}
virtual expr get_type() const { return m_type; }
@ -72,36 +188,45 @@ public:
return false;
}
}
virtual void display(std::ostream & out) const { out << Name; }
virtual format pp() const { return format(Name); }
virtual unsigned hash() const { return Hash; }
virtual void display(std::ostream & out) const { out << m_name; }
virtual format pp() const { return format(m_name); }
virtual unsigned hash() const { return m_name.hash(); }
};
constexpr char int_add_name[] = "+";
constexpr char int_add_name[] = "add";
struct int_add_eval { mpz operator()(mpz const & v1, mpz const & v2) { return v1 + v2; }; };
typedef int_bin_op<int_add_name, 43, int_add_eval> int_add_value;
typedef int_bin_op<int_add_name, int_add_eval> int_add_value;
MK_BUILTIN(int_add_fn, int_add_value);
constexpr char int_sub_name[] = "-";
constexpr char int_sub_name[] = "sub";
struct int_sub_eval { mpz operator()(mpz const & v1, mpz const & v2) { return v1 - v2; }; };
typedef int_bin_op<int_sub_name, 47, int_sub_eval> int_sub_value;
typedef int_bin_op<int_sub_name, int_sub_eval> int_sub_value;
MK_BUILTIN(int_sub_fn, int_sub_value);
constexpr char int_mul_name[] = "*";
constexpr char int_mul_name[] = "mul";
struct int_mul_eval { mpz operator()(mpz const & v1, mpz const & v2) { return v1 * v2; }; };
typedef int_bin_op<int_mul_name, 53, int_mul_eval> int_mul_value;
typedef int_bin_op<int_mul_name, int_mul_eval> int_mul_value;
MK_BUILTIN(int_mul_fn, int_mul_value);
constexpr char int_div_name[] = "div";
struct int_div_eval { mpz operator()(mpz const & v1, mpz const & v2) { return v1 / v2; }; };
typedef int_bin_op<int_div_name, 61, int_div_eval> int_div_value;
struct int_div_eval {
mpz operator()(mpz const & v1, mpz const & v2) {
if (v2.is_zero())
return v2;
else
return v1 / v2;
};
};
typedef int_bin_op<int_div_name, int_div_eval> int_div_value;
MK_BUILTIN(int_div_fn, int_div_value);
class int_le_value : public value {
expr m_type;
name m_name;
public:
int_le_value() {
m_type = Int >> (Int >> Bool);
m_name = name{"Int", "le"};
}
virtual ~int_le_value() {}
virtual expr get_type() const { return m_type; }
@ -114,20 +239,54 @@ public:
return false;
}
}
virtual void display(std::ostream & out) const { out << "Le"; }
virtual format pp() const { return format("Le"); }
virtual unsigned hash() const { return 67; }
virtual void display(std::ostream & out) const { out << m_name; }
virtual format pp() const { return format(m_name); }
virtual unsigned hash() const { return m_name.hash(); }
};
MK_BUILTIN(int_le_fn, int_le_value);
MK_CONSTANT(int_ge_fn, name(name("Int"), "ge"));
MK_CONSTANT(int_lt_fn, name(name("Int"), "lt"));
MK_CONSTANT(int_gt_fn, name(name("Int"), "gt"));
MK_CONSTANT(int_ge_fn, name(name("int"), "Ge"));
MK_CONSTANT(int_lt_fn, name(name("int"), "Lt"));
MK_CONSTANT(int_gt_fn, name(name("int"), "Gt"));
class nat_to_int_value : public value {
expr m_type;
name m_name;
public:
nat_to_int_value() {
m_type = Nat >> Int;
m_name = "nat_to_int";
}
virtual ~nat_to_int_value() {}
virtual expr get_type() const { return m_type; }
virtual bool operator==(value const & other) const { return dynamic_cast<nat_to_int_value const*>(&other) != nullptr; }
virtual bool normalize(unsigned num_args, expr const * args, expr & r) const {
if (num_args == 2 && is_nat_value(args[1])) {
r = mk_int_value(nat_value_numeral(args[1]));
return true;
} else {
return false;
}
}
virtual void display(std::ostream & out) const { out << m_name; }
virtual format pp() const { return format(m_name); }
virtual unsigned hash() const { return m_name.hash(); }
};
MK_BUILTIN(nat_to_int_fn, nat_to_int_value);
// =======================================
void add_int_theory(environment & env) {
expr p = Int >> (Int >> Bool);
expr p_ii = Int >> (Int >> Bool);
expr p_nn = Nat >> (Nat >> Bool);
expr x = Const("x");
expr y = Const("y");
env.add_definition(int_ge_fn_name, p, Fun({{x, Int}, {y, Int}}, iLe(y, x)));
env.add_definition(nat_ge_fn_name, p_nn, Fun({{x, Nat}, {y, Nat}}, nLe(y, x)));
env.add_definition(nat_lt_fn_name, p_nn, Fun({{x, Nat}, {y, Nat}}, Not(nLe(y, x))));
env.add_definition(nat_gt_fn_name, p_nn, Fun({{x, Nat}, {y, Nat}}, Not(nLe(x, y))));
env.add_definition(int_ge_fn_name, p_ii, Fun({{x, Int}, {y, Int}}, iLe(y, x)));
env.add_definition(int_lt_fn_name, p_ii, Fun({{x, Int}, {y, Int}}, Not(iLe(y, x))));
env.add_definition(int_gt_fn_name, p_ii, Fun({{x, Int}, {y, Int}}, Not(iLe(x, y))));
}
}

View file

@ -11,6 +11,35 @@ Author: Leonardo de Moura
#include "mpq.h"
namespace lean {
expr mk_nat_type();
extern expr const Nat;
expr mk_nat_value(mpz const & v);
inline expr mk_nat_value(unsigned v) { return mk_nat_value(mpz(v)); }
inline expr nVal(unsigned v) { return mk_nat_value(v); }
bool is_nat_value(expr const & e);
mpz const & nat_value_numeral(expr const & e);
expr mk_nat_add_fn();
inline expr nAdd(expr const & e1, expr const & e2) { return mk_app(mk_nat_add_fn(), e1, e2); }
expr mk_nat_mul_fn();
inline expr nMul(expr const & e1, expr const & e2) { return mk_app(mk_nat_mul_fn(), e1, e2); }
expr mk_nat_le_fn();
inline expr nLe(expr const & e1, expr const & e2) { return mk_app(mk_nat_le_fn(), e1, e2); }
expr mk_nat_ge_fn();
inline expr nGe(expr const & e1, expr const & e2) { return mk_app(mk_nat_ge_fn(), e1, e2); }
expr mk_nat_lt_fn();
inline expr nLt(expr const & e1, expr const & e2) { return mk_app(mk_nat_lt_fn(), e1, e2); }
expr mk_nat_gt_fn();
inline expr nGt(expr const & e1, expr const & e2) { return mk_app(mk_nat_gt_fn(), e1, e2); }
inline expr nIf(expr const & c, expr const & t, expr const & e) { return mk_if(Nat, c, t, e); }
expr mk_int_type();
extern expr const Int;
@ -46,6 +75,9 @@ inline expr iGt(expr const & e1, expr const & e2) { return mk_app(mk_int_gt_fn()
inline expr iIf(expr const & c, expr const & t, expr const & e) { return mk_if(Int, c, t, e); }
expr mk_nat_to_int_fn();
inline expr n2i(expr const & e) { return mk_app(mk_nat_to_int_fn(), e); }
class environment;
void add_int_theory(environment & env);
}

View file

@ -48,8 +48,8 @@ expr mk_bin_lop(expr const & op, expr const & unit, std::initializer_list<expr>
// =======================================
// Bultin universe variables m and u
static level m_lvl(name("m"));
static level u_lvl(name("u"));
static level m_lvl(name("M"));
static level u_lvl(name("U"));
expr const TypeM = Type(m_lvl);
expr const TypeU = Type(u_lvl);
// =======================================
@ -57,6 +57,7 @@ expr const TypeU = Type(u_lvl);
// =======================================
// Boolean Type
static char const * g_Bool_str = "Bool";
static name g_Bool_name(g_Bool_str);
static format g_Bool_fmt(g_Bool_str);
class bool_type_value : public value {
public:
@ -64,9 +65,9 @@ public:
virtual expr get_type() const { return Type(); }
virtual bool normalize(unsigned num_args, expr const * args, expr & r) const { return false; }
virtual bool operator==(value const & other) const { return dynamic_cast<bool_type_value const*>(&other) != nullptr; }
virtual void display(std::ostream & out) const { out << g_Bool_str; }
virtual void display(std::ostream & out) const { out << g_Bool_name; }
virtual format pp() const { return g_Bool_fmt; }
virtual unsigned hash() const { return 17; }
virtual unsigned hash() const { return g_Bool_name.hash(); }
};
expr const Bool = mk_value(*(new bool_type_value()));
expr mk_bool_type() { return Bool; }
@ -155,7 +156,7 @@ public:
virtual bool operator==(value const & other) const { return dynamic_cast<ite_fn_value const*>(&other) != nullptr; }
virtual void display(std::ostream & out) const { out << g_ite_name; }
virtual format pp() const { return g_ite_fmt; }
virtual unsigned hash() const { return 27; }
virtual unsigned hash() const { return g_ite_name.hash(); }
};
MK_BUILTIN(ite_fn, ite_fn_value);
// =======================================

View file

@ -160,9 +160,6 @@ expr mk_##Name() { \
static thread_local expr r = mk_value(*(new ClassName())); \
return r; \
} \
bool is_##Name(expr const & e) { \
return is_value(e) && dynamic_cast<ClassName const *>(&to_value(e)) != nullptr; \
}
/**
\brief Helper macro for generating "defined" constants.

View file

@ -24,7 +24,7 @@ static void scan(char const * str, list<name> const & cmds = list<name>()) {
std::cout << t;
if (t == st::Id || t == st::CommandId)
std::cout << "[" << s.get_name_val() << "]";
else if (t == st::IntVal || t == st::DecimalVal)
else if (t == st::NatVal || t == st::DecimalVal)
std::cout << "[" << s.get_num_val() << "]";
else if (t == st::StringVal)
std::cout << "[\"" << escaped(s.get_str_val().c_str()) << "\"]";
@ -78,11 +78,11 @@ static void tst2() {
check("x+y", {st::Id, st::Id, st::Id});
check("(* testing *)", {});
check(" 2.31 ", {st::DecimalVal});
check(" 333 22", {st::IntVal, st::IntVal});
check(" 333 22", {st::NatVal, st::NatVal});
check("Int -> Int", {st::Id, st::Arrow, st::Id});
check("Int --> Int", {st::Id, st::Id, st::Id});
check("x := 10", {st::Id, st::Assign, st::IntVal});
check("(x+1):Int", {st::LeftParen, st::Id, st::Id, st::IntVal, st::RightParen, st::Colon, st::Id});
check("x := 10", {st::Id, st::Assign, st::NatVal});
check("(x+1):Int", {st::LeftParen, st::Id, st::Id, st::NatVal, st::RightParen, st::Colon, st::Id});
check("{x}", {st::LeftCurlyBracket, st::Id, st::RightCurlyBracket});
check("\u03BB \u03A0 \u2192", {st::Lambda, st::Pi, st::Arrow});
scan("++\u2295++x\u2296\u2296");
@ -91,7 +91,7 @@ static void tst2() {
check_name("x10", name("x10"));
check_name("x::10", name(name("x"), 10));
check_name("x::10::bla::0", name(name(name(name("x"), 10), "bla"), 0u));
check("0::1", {st::IntVal, st::Colon, st::Colon, st::IntVal});
check("0::1", {st::NatVal, st::Colon, st::Colon, st::NatVal});
check_name("\u2296\u2296", name("\u2296\u2296"));
try {
scan("x::1000000000000000000");

17
tests/lean/arith1.lean Normal file
View file

@ -0,0 +1,17 @@
Check 10 + 20
Check 10
Check 10 - 20
Eval 10 - 20
Eval 15 + 10 - 20
Check 15 + 10 - 20
Variable x : Int
Variable n : Nat
Variable m : Nat
Show n + m
Show n + x + m
Set lean::pp::coercion true
Show n + x + m + 10
Show x + n + m + 10
Show n + m + 10 + x
Set lean::pp::notation false
Show n + m + 10 + x

View file

@ -0,0 +1,17 @@
Nat
Nat
Int
-10
5
Int
Assumed: x
Assumed: n
Assumed: m
n + m
n + x + m
Set option: lean::pp::coercion
(nat_to_int n) + x + (nat_to_int m) + (nat_to_int 10)
x + (nat_to_int n) + (nat_to_int m) + (nat_to_int 10)
(nat_to_int (n + m + 10)) + x
Set option: lean::pp::notation
Int::add (nat_to_int (Nat::add (Nat::add n m) 10)) x

View file

@ -5,7 +5,7 @@
Assumed: a
a ⊕ a ⊕ a
Π (A : Type u) (a b : A) (P : A → Bool) (H1 : P a) (H2 : a = b), P b
Π (A : Type U) (a b : A) (P : A → Bool) (H1 : P a) (H2 : a = b), P b
Proved: EM2
Π a : Bool, a ¬ a
a ¬ a

View file

@ -1,21 +1,21 @@
Set pp::colors false
Variable x : Type max u+1+2 m+1 m+2 3
Variable x : Type max U+1+2 M+1 M+2 3
Check x
Variable f : Type u+10 -> Type
Variable f : Type U+10 -> Type
Check f
Check f x
Check Type 4
Check x
Check Type max u m
Show Type u+3
Check Type u+3
Check Type u ⊔ m
Check Type u ⊔ m ⊔ 3
Show Type u+1 ⊔ m ⊔ 3
Check Type u+1 ⊔ m ⊔ 3
Show Type u -> Type 5
Check Type u -> Type 5
Check Type m ⊔ 3 -> Type u+5
Show Type m ⊔ 3 -> Type u -> Type 5
Check Type m ⊔ 3 -> Type u -> Type 5
Show Type u
Check Type max U M
Show Type U+3
Check Type U+3
Check Type U ⊔ M
Check Type U ⊔ M ⊔ 3
Show Type U+1 ⊔ M ⊔ 3
Check Type U+1 ⊔ M ⊔ 3
Show Type U -> Type 5
Check Type U -> Type 5
Check Type M ⊔ 3 -> Type U+5
Show Type M ⊔ 3 -> Type U -> Type 5
Check Type M ⊔ 3 -> Type U -> Type 5
Show Type U

View file

@ -1,21 +1,21 @@
Set option: pp::colors
Assumed: x
Type u+3 ⊔ m+2 ⊔ 3
Type U+3 ⊔ M+2 ⊔ 3
Assumed: f
Type u+10 → Type
Type U+10 → Type
Type
Type 5
Type u+3 ⊔ m+2 ⊔ 3
Type u+1 ⊔ m+1
Type u+3
Type u+4
Type u+1 ⊔ m+1
Type u+1 ⊔ m+1 ⊔ 4
Type u+1 ⊔ m ⊔ 3
Type u+2 ⊔ m+1 ⊔ 4
Type u → Type 5
Type u+1 ⊔ 6
Type m+1 ⊔ 4 ⊔ u+6
Type m ⊔ 3 → Type u → Type 5
Type m+1 ⊔ 6 ⊔ u+1
Type u
Type U+3 ⊔ M+2 ⊔ 3
Type U+1 ⊔ M+1
Type U+3
Type U+4
Type U+1 ⊔ M+1
Type U+1 ⊔ M+1 ⊔ 4
Type U+1 ⊔ M ⊔ 3
Type U+2 ⊔ M+1 ⊔ 4
Type U → Type 5
Type U+1 ⊔ 6
Type M+1 ⊔ 4 ⊔ U+6
Type M ⊔ 3 → Type U → Type 5
Type M+1 ⊔ 6 ⊔ U+1
Type U

View file

@ -9,7 +9,7 @@ f::explicit ((N → N) → N → N) (λ x :
Set option: pp::colors
EqNice::explicit N n1 n2
N
Π (A : Type u) (B : A → Type u) (f g : Π x : A, B x) (a b : A) (H1 : f = g) (H2 : a = b), (f a) = (g b)
Π (A : Type U) (B : A → Type U) (f g : Π x : A, B x) (a b : A) (H1 : f = g) (H2 : a = b), (f a) = (g b)
f::explicit N n1 n2
Assumed: a
Assumed: b

View file

@ -4,7 +4,7 @@ Show fun (A B : Type) (a : _), f B a
(* The following one should produce an error *)
Show fun (A : Type) (a : _) (B : Type), f B a
Variable myeq : Pi (A : Type u), A -> A -> Bool
Variable myeq : Pi (A : Type U), A -> A -> Bool
Show myeq _ (fun (A : Type) (a : _), a) (fun (B : Type) (b : B), b)
Check myeq _ (fun (A : Type) (a : _), a) (fun (B : Type) (b : B), b)