import data.num


variables int nat real : Type.{1}
variable nat_add  : nat → nat → nat
variable int_add  : int → int → int
variable real_add : real → real → real

inductive add_struct (A : Type) :=
mk : (A → A → A) → add_struct A

definition add {A : Type} {S : add_struct A} (a b : A) : A :=
add_struct.rec (λ m, m) S a b

infixl `+`:65 := add

definition add_nat_struct  [instance] : add_struct nat := add_struct.mk nat_add
definition add_int_struct  [instance] : add_struct int := add_struct.mk int_add
definition add_real_struct [instance] : add_struct real := add_struct.mk real_add

variables n m : nat
variables i j : int
variables x y : real
variable num_to_nat : num → nat
variable nat_to_int : nat → int
variable int_to_real : int → real
coercion num_to_nat
coercion nat_to_int
coercion int_to_real

set_option pp.implicit true
set_option pp.coercions true
check n + m
check i + j
check x + y
check i + n
check i + x
check n + i
check x + i
check n + x
check x + n
check x + i + n
check n + 0
check 0 + n
check 0 + i
check i + 0
check 0 + x
check x + 0
namespace foo
variable eq {A : Type} : A → A → Prop
infixl `=`:50 := eq
definition id (A : Type) (a : A) := a
notation A `=` B `:` C := @eq C A B
check nat_to_int n + nat_to_int m = (n + m) : int
end foo
