In Isabelle, integer literals (also called numerical constants) like ..., -2
, -1
, 0
, 1
, 2
, ... are overloaded.
There are type classes for zero (zero
), one (one
), positive numerals (numeral
), and negative numerals (neg_numeral
). The latter two also incorporate type classes for the additive semi-group (semigroup_add
) -- allowing for the use of +
-- and the additive group (group_add
) -- allowing for the use of +
and -
(also unary) -- respecively. (Also note that the plus sign itself (op +
) is overloaded in class plus
.)
Now, if you enter an expression, Isabelle infers the most general type. Often this is more general than one expects. This is exactly what you encountered. Consider some examples:
input inferred type type class
0 'a 'a::zero
1 'a 'a::one
op + 'a => 'a => 'a 'a::plus
1 + 2 'a 'a::numeral
x + y 'a 'a::plus
Suc 0 + y nat (nat is an instance, among others,
of class semigroup_add)
In such a situation you can tell the system that you mean a less general type by explicitly adding a type constraint, e.g., (1::nat) + 2
results in the overall type nat
.
If you use Isabelle/jEdit you can investigate such situations conveniently without introducing noise like declare [[...]]
in your theory. For example when entering
value "1 + 2"
in the Output panel you see
"1 + (1 + 1)"
:: "'a"
Now you can Ctrl-click (i.e, keep the control button pressed and click with the mouse) on the 'a
in the output. Which will tell you that 'a
is in class numeral
. You can further Ctrl-click numeral
to get to the definition of this type class.
If you change your input to (for natural numbers)
value "(1::nat) + 2"
or (for integers)
value "(1::int) + 2"
the output will be
"Suc (Suc (Suc 0)))" :: "nat"
and
"3" :: "int"
as expected.
Update: Note that natural numbers (type nat
) will be printed in unary representation like: 0
, Suc 0
, Suc (Suc 0)
, ... .
This is not to be confused with 1 + (1 + (1 + ...))
however (which is of arbitrary type of class numeral
). Such "Peano numbers" constitute proper natural numbers, as if nat
was defined as follows:
datatype nat = 0 | Suc nat
So this is merely about pretty-printing, but logically irrelevant.