Here is a very simple theory:
theory Test
imports HOLCF
begin
fixrec down :: "'a u → 'a"
where "down (up x) = x"
end
It gives the following error:
Type unification failed: Clash of types "_ ⇒ _" and "_ → _"
Type error in application: operator not of function type
Operator: up :: ??'a → ??'a⇩⊥
Operand: x :: ??'b
I have tried to declare different functions but I always get a similar error. What's a problem and how to fix it?
I tried to replace → by ⇒, but it doesn't help.
The single arrow → is the space of continuous functions whereas the double arrow ⇒ represents the space of all total functions. All packages in HOLCF only work with continuous functions. This is why ⇒ will not work for most of HOLCF. Function application for continuous functions, however, must be written explicitly using the ASCII infix operator $ or \<cdot>. So the following works:
fixrec down :: "'a u → 'a"
where "down $ (up $ x) = x"
Similarly, lambda abstractions for continuous functions use a capital Λ instead of a small λ.
Related
I have Isabelle definition:
definition two_integer_max_case_def :: "nat ⇒ nat ⇒ nat" where
"two_integer_max_case_def a b = (case a > b of True ⇒ a | False ⇒ b)"
with output
consts
two_integer_max_case_def :: "nat ⇒ nat ⇒ nat
And I can get value from this definition:
value "two_integer_max_case_def 3 4"
with output:
"4"
:: "nat"
So, this is recognizable and correct expression/term. But I tried to declare lemma using this definition:
lemma spec_1:
assumes "a: nat" "b: nat" "a > b"
shows "two_integer_max_case_def a b = a"
Unfortunately, this lemma is not accepted (no goals/subgoals are generated) and instead the error message is given:
Type unification failed: Clash of types "_ ⇒ _" and "_ set"
Type error in application: incompatible operand type
Operator: (∈) a :: ??'a set ⇒ bool
Operand: nat :: int ⇒ nat
What is wrong with my lemma? Am I just using incorrectly equality operation (maybe there are some subtleties - confusion of nat instances with sets of nat) or is it more general problem? Maybe I am not allowed to state theorems/lemmas for (possibly interminating) definitions and I can state lemmas only for functions for which the termination proof has been already done (at the time of statement of function)?
Is it possible to correct (in case if lemma can be stated for definition) my lemma so it gets accepted and generates goals for proof?
There is nothing inherently wrong with the lemma you propose, the only issue here is how the types of a and b are declared.
The expression a: nat is interpreted as a ∈ nat which produces a type error. The error message you're seeing says that the second argument to the ∈ operator, nat, should be of type 'a set but is int => nat.
In order to declare the types of variables in a lemma you can use the fixes keyword as below.
lemma spec_1:
fixes a :: nat and b :: nat
assumes "a > b"
shows "two_integer_max_case_def a b = a"
I have defined locale and proved a few theorems. Now I need to use them outside of this locale/context. How can I do so?
Can I obtain theorem with hypotheses extended by locale's assumptions? (Like it is done in Coq.)
locale mylocale =
assumes H1:‹a ∈ A›
begin
theorem thm:‹a∈A›
by (rule H1)
end
I need to obtain theorem "a∈A==>a∈A" from thm that is defined above. (I don't need exactly this theorem, it's just a simplest example of obtaining theorem with extended set of assumptions.(thm inside mylocale has zero hypotheses))
Every definition and theorem in a locale context generates a global version. You can access this global version (generalized over the locale parameters and extended with the locale assumptions) using locale_name.constant_name or locale_name.theorem_name. In your example, mylocale.thm gives you what you want.
If you need several theorems without the generalization of the locale parameters, you can interpret the locale in an unnamend context that has fixed the parameters and assumed the assumptions. Here's an example:
locale l = fixes a :: 'a assumes "a ~= undefined" begin
definition foo :: 'a where "foo = a"
lemma lem: "a = foo" by(simp add: foo_def)
end
thm l.lem (* a is generalized to ?a *)
consts bar :: nat
context assumes *: "bar ~= undefined" begin
interpretation bar: l bar by(fact bar)
thm lem (* a is instantiated with bar *)
end
Is there a way to define syntactic replacements for types in Isabelle/HOL?
I want to do something like this:
syntax my_short_list :: "type" ("my-list")
translations "my_short_list" ⇌ (type) "'a list" ― ‹Could not find syntax to express this ...›
locale foo =
fixes blub :: "my-list ⇒ my-list"
And want this to be interpreted like this:
locale foo =
fixes blub :: "'a list ⇒ 'a list"
(all occurrences of my-list are replaced with the text 'a list)
The above produces the following error:
Error in syntax translation rule: rhs contains extra variables
"my_short_list" ↝ ("\<^type>List.list" 'a)
So I am looking for a variant that is a purely syntactic replacement without any macro hygiene checks.
Some background to understand the underlying problem:
I have a locale with 5 type parameters and a datatype X that takes all 5 type parameters, so for every use I have to write ('a, 'b, 'c, 'd, 'e) X. Obviously the names are longer in practice so this becomed even more unreadable.
Other approaches I tried:
Defining the types or a type_synonym in my locale.
This is not allowed (see https://stackoverflow.com/a/19281758/303637).
Just using another type parameter to represent ('a, 'b, 'c, 'd, 'e) X and assumes for all the required properties of the data type.
This is a lot of boilerplate since I need to write down all the properties that are usually automatically generated for datatype definitions.
Consider the following Isabelle/HOL definition of a simple process language:
typedecl channel
datatype process = Put channel char process | Get "char ⇒ process" | Stop
This languages supports sending and receiving of characters via channels.
Now I’d like to have typed channels. The channel type should have the type of values it can transport as a parameter:
typedecl 'a channel
The Put and Get data constructors should have the following (polymorphic) types:
Put :: "['a channel, 'a, process] ⇒ process"
Get :: "['a channel, 'a ⇒ process] ⇒ process"
However, this requires support for existential quantification in data types, which Isabelle/HOL doesn’t have.
I tried to fake existential quantification and came up with the following attempt:
typedecl put
axiomatization put :: "['a channel, 'a] ⇒ put" where
put_inject: "put a x = put b y ⟷ a = b ∧ x = y"
bnf_axiomatization 'r get
axiomatization get :: "['a channel, 'a ⇒ 'r] ⇒ 'r get" where
get_inject: "get a f = get b g ⟷ a = b ∧ f = g"
datatype process = Put put process | Get "process get" | Stop
Unfortunately, this results in the following error message:
Type definition with open dependencies, use "typedef (overloaded)" or enable configuration option "typedef_overloaded" in the context.
Type: process
Deps:
map_get(process.process_IITN_process
⇒ (process_pre_process_bdT + process_pre_process_bdT process_pre_process) set ⇒ bool,
(process_pre_process_bdT + process_pre_process_bdT process_pre_process) set ⇒ bool),
bd_get,
set_get(process.process_IITN_process
⇒ (process_pre_process_bdT + process_pre_process_bdT process_pre_process) set ⇒ bool)
The error(s) above occurred in typedef "process"
Is my attempt reasonable, and, if yes, how can I solve this problem? Is there a better solution?
Indeed, the axiom for get is inconsistent with the bnf_axiomatization. However, if you restrict yourself to countable types 'a, then such a type exists. As soon as you fix such a cardinality bound, you do not even have to restort to axiomatization. Existential types can then be emulated within HOL using encoding and decoding functions into/from a universal domain.
For example, for countable types, the natural numbers can be used as the universal domain. This has been used, e.g., in Imperative_HOL to model a heap that can store typed values, see the paper from 2008. Huffman has done something similar for HOLCF, Isabelle's domain theory library.
With such an encoding in place, you'd construct the datatype of processes using untyped channels and then create a type-safe view on the datatype using the encoding and decoding functions as necessary.
(NOTE: If I can get rid of the warning I show below, then I say a bunch of extraneous stuff. As part of asking a question, I also do some opinionating. I guess that's sort of asking the question "Why am I wrong here in what I say?")
It seems that 6 of the symbols used for bool operators should have been assigned to syntactic type classes, and bool instantiated for those type classes. In particular, these:
~, &, |, \<not>, \<and>, \<or>.
Because type annotation of terms is a frequent requirement for HOL operators, I don't think it would be a great burden to have to use bool annotations for those 6 operators.
I would like to overload those 6 symbols for other logical operators. Not having the usual symbols for an application can result in there being no good solution for notation.
In the following example source, if I can get rid of the warnings, then the problem is solved (unless I would be setting a trap for myself):
definition natOP :: "nat => nat => nat" where
"natOP x y = x"
definition natlistOP :: "nat list => nat list => nat list" where
"natlistOP x y = x"
notation
natOP (infixr "&" 35)
notation
natlistOP (infixr "&" 35)
term "True & False"
term "2 & (2::nat)"
term "[2] & [(2::nat)]" (*
OUTPUT: Ambiguous input produces 3 parse trees:
...
Fortunately, only one parse tree is well-formed and type-correct,
but you may still want to disambiguate your grammar or your input.*)
Can I get rid of the warnings? It seems that since there's a type correct term, there shouldn't be a problem.
There are actually other symbols I also want, such as !, used for list:
term "[1,2,3] ! 1"
Here's the application for which I want the symbols:
Verilog HDL Operators.
Update
Based on Brian Huffman's answer, I unnotate &, and switch & to a syntactic type class. It'll work out, or it won't, indeed, binary logic, so diversely applicable. My general rule is "don't mess with default Isabelle/HOL".
(*|Unnotate; switch to a type class; see someday why this is a bad idea.|*)
no_notation conj (infixr "&" 35)
class conj =
fixes syntactic_type_classes_are_awesome :: "'a => 'a => 'a" (infixr "&" 35)
instantiation bool :: conj
begin
definition syntactic_type_classes_are_awesome_bool :: "bool => bool => bool"
where "p & q == conj p q"
instance ..
end
term "True & False"
value "True & False"
declare[[show_sorts]]
term "p & q" (* "(p::'a::conj) & (q::'a::conj)" :: "'a::conj" *)
You can "undeclare" special syntax using the no_notation command, e.g.
no_notation conj (infixr "\<and>" 35)
This infix operator is then available to be used with your own functions:
notation myconj (infixr "\<and>" 35)
From here on, \<and> refers to the constant myconj instead of the HOL library's standard conjunction operator for type bool. You should have no warnings about ambiguous syntax. The original HOL boolean operator is still accessible by name (conj), or you can give it a different syntax if you want with another notation command.
For the no_notation command to work, the pattern and fixities must be exactly the same as they were declared originally. See src/HOL/HOL.thy for the declarations of the operators you are interested in.
I should warn about a potential pitfall: Subsequent theory merges can bring the original syntax back into scope, causing ambiguous syntax again. For example, say your theory A.thy imports Main and redeclares the \<and> syntax. Then your theory B.thy imports both A and another library theory, say Complex_Main. Then in theory B, \<and> will be ambiguous. To prevent this, make sure to put all your external theory imports in the one theory file where you change the syntax; then have all of your other theories import this one.