Isabelle: Evaluating formula with Quantifiers - isabelle

Why does the following work:
fun f :: "nat ⇒ bool" where
"f _ = (True ∨ (∀x. x))"
But this fails
fun g :: "nat ⇒ bool" where
"g _ = (True ∨ (∀a. True))"
with
Additional type variable(s) in specification of "g_graph": 'a
Specification depends on extra type variables: "'a"
The error(s) above occurred in "test.g_sumC_def"
The error(s) above occurred in definition "g_sumC_def":
"g_sumC ≡ λx. THE_default undefined (g_graph TYPE('a) x)"
Similarly, the following succeeds,
value "True ∨ (∀x. x)"
but this fails
value "True ∨ (∀x. True)"
with
Wellsortedness error:
Type 'a not of sort enum
Cannot derive subsort relation {} < enum

The short answer is: In your first function definition type inference easily infers that x is of type bool, while in your second definition, the bound variable a is not used anywhere else and thus its type is arbitrary ('a). Which is what Additional type variable(s) in specification ... expresses.
If you constrain the type of a explicitly, e.g.,
fun g :: "nat ⇒ bool" where
"g _ = (True ∨ (∀a::bool. True))"
the function definition is accepted.
A longer answer: Since the definition of g is not recursive you could turn it into using definition instead of fun. Then your first attempt does not fail completely but the result might surprise you. After
definition g :: "nat ⇒ bool" where
"g _ = (True ∨ (∀a. True))"
the type of g is 'a itself => nat => bool instead of the intended nat => bool. The reason is the same as for the failure of fun before. Since a is of arbitrary type, this additional type has to be recorded in the type of g, which is done by introducing an additional dummy argument which just states this additional type explicitly. Here 'a itself is a type whose constructor TYPE(...) -- taking a type as argument -- allows us to encode type information on the term level. E.g.,
TYPE('a) :: 'a itself
TYPE(bool) :: bool itself
TYPE(nat) :: nat itself
Then g TYPE(nat) is the version of g where a is fixed to be of type nat.
Concerning your value statements, the reason for the second one to fail is not really related to the above. In the first statement the universal quantifier binds a variable of type bool whose values can be enumerated explicitly and thus a result can be computed by considering all those values. In contrast, in your second statement the bound variable x is of an arbitrary type 'a whose values cannot be enumerated explicitly.

The following fails:
fun f where "f _ = (∀a. True)"
because the type of a has hidden polymorphism (i.e., there is a type variable inside your function's body that is not present in the function's type signature), which upsets the function package's internal proofs.
If you explicitly give a a type as so:
fun f where "f _ = (∀a::bool. True)"
or is you give a a type that is also in the function's type signature, as so:
fun f where "f _ = (∀a::bool. True)"
the function definition succeeds. Your example:
fun f where "f _ = (∀x. x)"
succeeds, because x is forced to be type bool.
As for your value commands, Isabelle attempts to generate executable code for your expression, and hence needs to not only know the type of your for-all statements, but also be able to enumerate all possible values of it, so that it can test them all. Types such as bool work fine, but type variables like 'a or infinite types such as nat are not enumerable, and hence Isabelle cannot generate code for them.

Related

How to use type's argument as a value in a function?

I'm trying to define a simple type system with a custom set type:
notation bot ("⊥")
typedef 'a myset = "UNIV :: 'a fset option set" ..
copy_bnf 'a myset
setup_lifting type_definition_myset
lift_definition myset :: "'a fset ⇒ 'a myset" is Some .
instantiation myset :: (type) bot
begin
lift_definition bot_myset :: "'a myset" is None .
instance ..
end
free_constructors case_myset for
myset
| "⊥ :: 'a myset"
apply (simp_all add: bot_myset_def myset_def)
apply (metis Rep_myset_inverse option.collapse)
apply (metis Abs_myset_inverse iso_tuple_UNIV_I option.inject)
apply (metis Abs_myset_inverse iso_tuple_UNIV_I option.distinct(1))
done
lift_definition map_myset :: "('a ⇒ 'b) ⇒ 'a myset ⇒ 'b myset"
is "map_option ∘ fimage" .
Type system has integer, real and set types:
datatype type =
IType
| RType
| SType type
Also there are 3 kinds of values:
datatype val =
IVal int
| RVal real
| SVal "val myset"
I need to define a function type_of which determines a type of a value:
fun elem_type :: "val myset ⇒ type" and
type_of :: "val ⇒ type" where
"elem_type xs = ???"
| "type_of (IVal x) = IType"
| "type_of (RVal x) = RType"
| "type_of (SVal x) = SType (elem_type x)"
value "type_of (SVal (myset {|IVal 1, IVal 2|}))"
value "type_of (SVal (myset {|RVal 1, RVal 2|}))"
value "type_of (SVal (myset {|SVal (myset {|IVal 1|})|}))"
Could you suggest how to get element type of myset?
I would say there is a fundamental problem with your modelling: your type_of function seems to suggest that every value has exactly one type.
In his comment, Lars has already pointed out that there are some values (e.g. a set containing both integers and real values) that you would probably consider to be invalid and that therefore have no type at all. That you could handle by returning ‘undefined’ or something like that, perhaps, and introduce some kind of additional ‘well-formedness’ predicate for values, but I'm not sure that's a good idea.
Another problem is that there are some values that are polymorphic, i.e. that have more than one type, in a sense: For instance, what should your type_of function return for the empty set, i.e. SVal (myset {|})? There are infinitely many reasonable types that this thing could have.
The usual approach to handle this is to introduce a typing relation instead of a typing function so that each value can have several types – or none at all. Usually, you do this with the inductive command, defining an inductive predicate like has_type v t which states that the value v has the type t (or ‘can be given the type t’ in case of polymorphism).
Also, on an unrelated note, I am not sure why you define a new type and use copy_bnf, free_constructors etc. I don't know what you're planning to do but my guess would be that whatever it is does probably not get easier with that typedef; it will probably just cause some annoyances.

How to use Isabelle's code_pred and values commands?

There is an example of code_pred usage in "Concrete Semantics" by Tobias Nipkow and Gerwin Klein, Section 7.2.2. I've implemented a simple language based on the examples and I try to calculate values of expressions:
theory BooLang
imports Main
begin
type_synonym id = string
type_synonym 'a Env = "id ⇒ 'a"
datatype BooBoolExp =
BooLiteralExp bool |
BooLetExp id BooBoolExp BooBoolExp |
BooVarExp id |
BooAndExp BooBoolExp BooBoolExp
datatype BooVal = Bv bool
type_synonym BooEnv = "BooVal Env"
inductive tbooval :: "BooBoolExp × BooEnv ⇒ BooVal ⇒ bool" (infix "⇒" 55) where
Literal: "(BooLiteralExp b, env) ⇒ Bv b" |
And: "⟦(a, env) ⇒ Bv av; (b, env) ⇒ Bv bv⟧ ⟹ (BooAndExp a b, env) ⇒ Bv (av ∧ bv)" |
Var: "(BooVarExp v, env) ⇒ env v" |
Let: "⟦(val, env) ⇒ b; (body, env(v := b)) ⇒ x⟧ ⟹ (BooLetExp v val body, env) ⇒ x"
code_pred tbooval .
values "{t. True}"
values "{t. (BooLiteralExp true, λ_. Bv false) ⇒ t}"
end
But for the 1st values' invocation I get the error:
Evaluation with values is not possible because compilation with
code_pred was not invoked.
And for the 2nd one I get the error:
No mode possible for comprehension {t. (BooLiteralExp true, λ_. Bv
false) ⇒ t}.
What's wrong with my theory?
The first command values {t. True} cannot work as this command asks Isabelle to enumerate all values of the type of t, which is inferred to be a type variable 'a; and this cannot be done.
For the second command, you just misspelled True and False. As is, true and false are inferred to be boolean variables instead of boolean constants. Unlike value, the command values does not support symbolic execution in Isabelle2016-1. That is, all input arguments to the inductive predicate must be ground values without variables. In your example, code_pred infers two execution modes: One in which everything is given as input and one in which only the first argument is given as input. You can see the inferred modes by passing the [show_modes] option as in
code_pred [show_modes] tboolval .
You can find some further documentation on code_pred and values in the code generator tutorial.

Isabelle unification error

I am new to Isabelle and this is a simplification of my first program
theory Scratch
imports Main
begin
record flow =
Src :: "nat"
Dest :: "nat"
record diagram =
DataFlows :: "flow set"
Transitions :: "nat set"
Markings :: "flow set"
fun consume :: "diagram × (nat set) ⇒ (flow set)"
where
"(consume dia trans) = {n . n ∈ (Markings dia) ∧ (∃ t ∈ trans . (Dest n) = t)}"
end
The function give the error:
Type unification failed: Clash of types "_ ⇒ " and " set"
Type error in application: operator not of function type
Operator: consume dia :: flow set
Operand: trans :: (??'a × ??'a) set ⇒ bool
What should I do for the the code to compile?
First of all, you give two parameters to your consume function, but the way you defined its type, it takes a single tuple. This is unusual and often inconvenient – defined curried functions instead, like this:
fun consume :: "diagram ⇒ (nat set) ⇒ (flow set)"
Also, trans is a constant; it is the property that a relation is transitive. You can see that by observing that trans is black to indicate that it is a constant and the other variable is blue, indicating that it is a free variable.
I therefore recommend using another name, like ts:
where
"consume dia ts = {n . n ∈ (Markings dia) ∧ (∃ t ∈ ts . (Dest n) = t)}"

Isabelle type unification/inference error

I'm just getting started in Isabelle and I'm getting a type unification error while working through Exercise 3.3 in of Concrete Semantics:
Define a substitution function
subst :: vname ⇒ aexp ⇒ aexp ⇒ aexp
such that subst x a e is the result of replacing every occurrence of variable x by a in e. For example:
subst ''x'' (N 3) (Plus (V ''x'') (V ''y'')) = Plus (N 3) (V ''y'')
Here's what I've got so far:
theory Scratchpad
imports Main
begin
type_synonym vname = string
type_synonym val = int
type_synonym state = "vname ⇒ val"
datatype aexp = N int | V vname | Plus aexp aexp
fun subst :: "vname ⇒ aexp ⇒ aexp ⇒ aexp" where
"subst x (N a) (N e) = (N e)" |
"subst x (N a) (V e) = (if x=e then (N a) else (V e))" |
"subst x (N a) (Plus e1 e2) = Plus(subst(x (N a) e1) subst(x (N a) e2))"
end
When the third case in the function definition is commented out, running the test cases
value "subst ''x'' (N 3) (N 5)"
value "subst ''x'' (N 3) (V ''x'')"
produces (N 5) and (N 3) respectively, so I know the first two lines are working correctly. Adding the last line results in the error
Type unification failed: Clash of types "_ ⇒ _" and "_ list"
Type error in application: operator not of function type
Operator: x :: char list
Operand: N a :: aexp
I don't think this is a syntax issue, although I'm not yet completely sure what purposes different types of quotation marks serve (e.g. double quotes vs. two single quotes). From this answer, I believe that Isabelle is assigning x to be a function type on the right side of the line, which is not what I want.
What do the error messages actually mean (specifically and generally), and how do I fix this?
To answer your question about quotes: Two single quotes are used in Isabelle/HOL (more precisely its inner syntax) to denote string literals. That is, by ''abc'' we denote the string containing the three characters a, b, and c (which would again use some special syntax if you had to enter them literally). Double quotes on the other hand, are mostly used to separate Isar statements (outer syntax) from terms inside the logic. So while ''...'' is part of the term language, "..." is not.
Now for the error message. It tells you that you are trying to use the list x (type _ list) as a function (type _ => _). Why does Isabelle think you want to use x as a function? Well, because juxtaposition (i.e., writing terms next to each other, separated by white space) denotes function application. Thus x (N a) is interpreted as applying a function x to an argument (N a) (just as f y is the application of f to the argument y). In order to give your definition the correct meaning you have to use parenthesis at the right positions. I guess what you intended in your third clause was:
Plus (subst x (N a) e1) (subst x (N a) e2)
where we have two occurrences of the function subst applied to three arguments. (So it was a syntax issue after all ;).)
Another comment. Your implementation of subst could be more general. As is, the second argument of subst is always fixed to be some number a (because of your usage of the constructor N). However, everything should work just as well if you would allow arbitrary expressions of type aexp.

Using tuples in definitions

I want to create a definition which has a tuple as its argument.
definition my_def :: "('a × 'a) ⇒ bool" where
"my_def (a, b) ⟷ a = b"
However, this is not accepted. The error message is
Bad arguments on lhs: "(a, b)"
The error(s) above occurred in definition:
"my_def (a, b) ≡ a = b"
Using fun instead of definition works but this is not what I want. The following notation also works but is somewhat ugly:
definition my_def :: "('a × 'a) ⇒ bool" where
"my_def t ⟷ fst t = snd t"
What is the best way to use tuples as arguments in a definition?
Using fun is probably the least painful way to do this, the definition package doesn't recognise patterns on the left hand side.
Another option is to use tuple patterns for lambda expressions:
my_def ≡ %(a,b). a = b

Resources