Infix relation transformer syntax in Isabelle - syntax

Given
notation
rtranclp ("(_^**)" [1000] 1000)
I can write, given an infix op ⇒
"op ⇒⇧*⇧* x x'"
but not the much more readable and prettier
"x ⇒⇧*⇧* x'"
I know that for every concrete relation (⇒ in this case), I can set up an abbreviation for this. But can I also solve this generally, i.e. for any infix relation?
If yes, can I extend that to multiple relations and other arguments? For example, given two infix relations ⇒ and ▹, and another term y I want to set it up so that I can write
x (⇒;▹)⇗y⇖ x'
(note the infix use) instead of
foo op ⇒ op ▹ y x x'
(where, in my case, has type foo :: ('a ⇒ 'a ⇒ bool) ⇒ ('a ⇒ 'b ⇒ bool) ⇒ 'b ⇒ 'a ⇒ 'a).

I believe that a general solution for all infix relations is not possible, because the parser does not know about the relation symbols in isolation. As can be seen from the implementation in mixfix.ML, an infix declaration with relation symbol < is equivalent to two mixfix declarations, namely "op <" and "(_ < _)" with appropriate precedences.
However, there is a more generic and elegant solution than to introduce abbreviations for all combinations of predicates and predicate transformers. First, introduce a syntactic category for relational symbols. To also get the right output, add a syntactic marker _infix
nonterminal rel
syntax (output) "_infix" :: "rel ⇒ logic" ("_")
Then, declare a syntax constant _rtranclp_rel for infix use with infix relations.
syntax "_rtranclp_rel" :: "logic ⇒ rel ⇒ logic ⇒ logic" ("(_ _⇧*⇧* _)")
translations "_rtranclp_rel x R y" ⇀ "CONST rtranclp R x y"
translations "_rtranclp_rel x (_infix R) y" ↽ "CONST rtranclp R x y"
Now, add a syntax translation to your relation rel that you want to use with _rtranclp_rel:
consts rel :: "nat ⇒ nat ⇒ bool" (infix "⇒" 100)
syntax "_rel_infix" :: rel ("⇒")
translations "_rel_infix" ⇀ "CONST rel"
translations "_rel_infix" ↽ "_infix (CONST rel)"
Then, Isabelle should be able to correctly parse and pretty-print x ⇒⇧*⇧* z. Note, however, that all fully applied instances of rtranclp are pretty-printed infix (e.g., rtranclp R x y, independent of whether the relation is an infix symbol.
This mechanism then also works for your function foo:
consts foo :: "('a ⇒ 'a ⇒ bool) ⇒ ('b ⇒ 'b ⇒ bool) ⇒ 'b ⇒ 'a ⇒ 'a ⇒ bool"
syntax "_foo_rel" :: "logic ⇒ rel ⇒ rel ⇒ logic ⇒ logic ⇒ logic" ("_ '(_;_')⇗_⇖ _")
translations "_foo_rel x R S y z" ⇀ "CONST foo R S x y z"
translations "_foo_rel x (_infix R) (_infix S) y z" ↽ "CONST foo R S x y z"
Of course, the precedences in the mixfix annotations should be adjusted to sensible ones. It is even possible to do this recursively. For example:
syntax "_rtranclp_rel2" :: "rel ⇒ rel" ("_⇧*⇧*")
translations "_rtranclp_rel2 R" ⇀ "CONST rtranclp R"
translations "_rtranclp_rel2 (_infix R)" ↽ "_infix (CONST rtranclp R)"
term "x (⇒⇧*⇧*;⇒)⇗y⇖ z"

Related

How to write bigvee and big wedge in Isabelle

I'm trying to use Isabelle to do auto-prove. However, I got a problem of specifying formulas in Isabelle. For example, I have a formulas like this
Then, I define sets and use big_wedge and big_vee symbols in Isabelle as follows:
And the result is "Inner lexical error⌂ Failed to parse prop".
Could you explain what is wrong here, please?
Thank you very much.
Not all symbols shown in Isabelle/jEdit's Symbol tabs have a meaning. These are the symbols you can use in your code.
Based on the corresponding code for sums, I started the setup, but I did not finish it (in particular, the syntax ⋀t!=l. P t is not supported).
context comm_monoid_add
begin
sublocale bigvee: comm_monoid_set HOL.disj False
defines bigvee = bigvee.F and bigvee' = bigvee.G
by standard auto
abbreviation bigvee'' :: ‹bool set ⇒ bool› ("⋁")
where "⋁ ≡ bigvee (λx. x)"
sublocale bigwedge: comm_monoid_set HOL.conj True
defines bigwedge = bigwedge.F and bigwedge' = bigwedge.G
by standard auto
abbreviation bigwedge'' :: ‹bool set ⇒ bool› ("⋀")
where "⋀ ≡ bigwedge (λx. x)"
end
syntax
"_bigwedge" :: "pttrn ⇒ 'a set ⇒ 'b ⇒ 'b::comm_monoid_add" ("(2⋀(_/∈_)./ _)" [0, 51, 10] 10)
translations ― ‹Beware of argument permutation!›
"⋀i∈A. b" ⇌ "CONST bigwedge (λi. b) A"
syntax
"_bigvee" :: "pttrn ⇒ 'a set ⇒ 'b ⇒ 'b::comm_monoid_add" ("(2⋁(_/∈_)./ _)" [0, 51, 10] 10)
translations ― ‹Beware of argument permutation!›
"⋁i∈A. b" ⇌ "CONST bigvee (λi. b) A"
instantiation bool :: comm_monoid_add
begin
definition zero_bool where
[simp]: ‹zero_bool = False›
definition plus_bool where
[simp]: ‹plus_bool = (∨)›
instance
by standard auto
end
thm bigvee_def
lemma ‹finite A ⟹ (⋁i∈A. f i) ⟷ (∃i ∈ A. f i)›
apply (induction rule: finite_induct)
apply (auto simp: )
done
lemma ‹finite A ⟹ (⋀i∈A. f i) ⟷ A = {} ∨ (∀i ∈ A. f i)›
apply (induction rule: finite_induct)
apply (auto simp: )[2]
done
lemma ‹infinite A ⟹ (⋀i∈A. f i) ⟷ True›
by auto
lemma test1:
‹(⋀j∈L. ⋀u∈U. ⋀t∈T. ⋀l∈L. ⋀l⇩1∈L⇩1. ¬P j u t l⇩1) ∨
(⋁i∈I. ⋁v∈V. ⋀k∈K. ⋁h∈H. Q i ∨ k h) ⟹
(⋁i∈I. ⋁v∈V. ⋀k∈K. ⋁h∈H. Q i ∨ k h) ∨ (⋀j∈J. ⋀u∈U. ⋀t∈T. ⋀l⇩1∈L⇩1. ¬P j u t l⇩1)›
apply auto
The full setup is possible. But I am not certain that this is a good idea... You will need a lot of lemmas to make things work nicely and I am not certain the behaviour for infinite sets is the right one.

Isabelle: How can I position fixed arguments in mixfix notation?

Say I have the following definition of a reflexive and transitive closure of a relation, where relations are represented by binary predicates:
inductive
closure :: "(['a, 'a] ⇒ bool) ⇒ (['a, 'a] ⇒ bool)"
for ℛ (infix "→" 50)
where
gen:
"x → y ⟹ closure (→) x y" |
refl:
"closure (→) x x" |
trans:
"⟦closure (→) x y; closure (→) y z⟧ ⟹ closure (→) x z"
I want to have a nicer syntax for applications of closure. Say I’d like to be able to write x *(→)* y for closure (→) x y. The problem is that the argument order in this notation doesn’t match the argument order of the function closure.
I thought that perhaps the use of \<index> could help. Unfortunately, the documentation of \<index> in the Isabelle/Isar Reference Manual is very terse, and I couldn’t really make sense of it. I played a bit with \<index> but didn’t find any workable solution.
What puzzled me was that apparently \<index> gets translated to ⇘some_index⇙, judging from some error messages I got. I tried to use ⇘ℛ⇙ to mark the position where the base relation should go, but this didn’t work either.
To switch the arguments, an abbreviation is the best choice. (syntax/translations works, too, but abbreviations should be preferred because they work in any context (locales, type classes, ...) and are type-checked.) Fortunately, inductive allows you to simultaneously declare abbreviations together with an inductive definition. The equations for the abbreviations have to come first. Here's how it works for your example:
inductive closure :: "(['a, 'a] ⇒ bool) ⇒ (['a, 'a] ⇒ bool)"
and closure_syntax :: "['a, ['a, 'a] ⇒ bool, 'a] ⇒ bool" ("(_ ⇧*(_)⇧* _)" [999,0,999] 100)
for ℛ (infix "→" 50)
where
"x ⇧*(→)⇧* y ≡ closure (→) x y"
| gen: "x → y ⟹ x ⇧*(→)⇧* y"
| refl: "x ⇧*(→)⇧* x"
| trans: "⟦x ⇧*(→)⇧* y; y ⇧*(→)⇧* z⟧ ⟹ x ⇧*(→)⇧* z"
The syntax element \<index> is rarely used nowadays, because locales achieve a similar effect and are usually more flexible. The point of \<index> is that you can declare a parameter as (structure) and this will then automatically be inserted whereever the parser sees \<index> in the syntax grammar. So it allows you to omit repeating the structure parameter, but locales usually work better.
You'd probably want to use syntax and translations, for example:
syntax "_closure" :: "['a, (['a, 'a] ⇒ bool), 'a] ⇒ (['a, 'a] ⇒ bool)" ("(_ *'(_')* _)")
translations "x *(ℛ)* y" ⇌ "CONST closure (ℛ) x y"
These are also documented in isar-ref.pdf, with some examples floating around in the source theory files (a hypersearch should turn these up).

\<setminus> Isabelle syntax

I just cant find the syntax for removing a term from a set.
I have the following:
typedecl STUDENT
definition LeaveHall ::
"STUDENT set => STUDENT set => STUDENT set => STUDENT set => STUDENT =>
bool"
where
"LeaveHall badminton' badminton hall' hall leaver ==
(
(leaver \<in> hall) \<and> (hall' = hall \<setminus> {(leaver)})
<and>
(badminton' = badminton)
)"
What it doesnt like i the expression "(hall' = hall \ {(leaver)})
"
I'm trying to say is the set hall' is the set hall minus the term leaver.
But it just doesnt like it. Ive tried putting brackets and things and it
still doesnt work.
While the ∖ symbol exists in Isabelle under the name \<setminus>, it is not used at the moment. The proper syntax for set difference is quite simply -, so this works:
definition LeaveHall :: "STUDENT set ⇒ STUDENT set ⇒ STUDENT set ⇒ STUDENT set ⇒ STUDENT ⇒ bool"
where "LeaveHall badminton' badminton hall' hall leaver ⟷
leaver ∈ hall ∧ hall' = hall - {leaver} ∧ badminton' = badminton"
If you want to use \<setminus>, you can, of course, define an abbreviation with that syntax:
abbreviation setminus (infixl "∖" 65) where "setminus ≡ op -"
Or, to only allow this to input terms but not use it when printing terms:
abbreviation (input) setminus (infixl "∖" 65) where "setminus ≡ op -"
On an unrelated note: identifiers consisting of multiple words are typically written with underscores in Isabelle as opposed to Camel Case. Of course, you can call your identifiers whatever you want, but the convention is to use underscores instead of Camel Case.
Also, note that I used ⟷ in the definition of LeaveHall above, not the meta equality ≡ (as you did) or regular equality =. The use of the meta equality operator ≡ in definitions is discouraged (although it has no real disadvantages).
The Boolean equivalence operator ⟷ is simply an abbreviation for equality on Booleans (so it's exactly the same as writing =). So why use ⟷? Because it has lower precedence than =, which means you typically need fewer parentheses: P a = Q a ∧ R a is parsed as (P a = Q a) ∧ R a, whereas P a ⟷ Q a ∧ R a is parsed as P a = (Q a ∧ R a).

Custom Isabelle syntax breaks existing syntax

I am attempting to generate a nice syntax for mapping a function over the values of an associative list, i.e. I want to write [x ↦ f y | (x ↦ y) ∈ l] for mapAList f l. I came up with
syntax
"_alist_map" :: "['b, pttrn, ('a × 'b) list] ⇒ ('a × 'b) list"
("[x ↦ _ | '(x ↦ _') ∈ _]")
which works, but causes term "(x,y)#[]" to tell me Inner syntax error at "(x , y ) # []" and the (x is shaded slightly different.
The reason seems that once x appears in a mixfix annotation, it now always a literal token to the grammer (a delimiter according to §7.4.1 of isar-ref) and no longer an identifier – just like the syntax for if ... then ... else ... prevents if from being a variable name
Can I somehow work around this problem?
Identifier names used in mixfix annotations cannot be used as identifiers any longer, and I don't know any way around that. Therefore, instead of using x as a variable name, you can pick a non-identifier symbol like \<xX> or \<mapAListvariable> and setup the LaTeX output to print this as x by adding \newcommand{\isasymmapAListvariable}{x} to your root.tex.
You can also add \<xX> or \<mapAListvariable> to the symbols file of Isabelle/JEdit (preferably in $ISABELLE_HOME_USER/etc/symbols) and assign it some Unicode point that will be used for display in Isabelle/JEdit.
I just made a small experiment with a function map_alist that hopefully corresponds to your mapAList and which is defined as follows:
fun map_alist :: "('b ⇒ 'c) ⇒ ('a × 'b) list ⇒ ('a × 'c) list"
where
"map_alist f [] = []" |
"map_alist f ((x, y) # xs) = (x, f y) # map_alist f xs"
Then existing syntax can be used which looks a little bit as you intended. Maybe this is an option?
lemma "map_alist f xs = [(x, f y). (x, y) ← xs]"
by (induct xs) auto

Isabelle syntax translations: Force eta-expansion?

Isabelle’s List theory has set up a syntax translation for filter:
syntax
-- {* Special syntax for filter *}
"_filter" :: "[pttrn, 'a list, bool] => 'a list" ("(1[_<-_./ _])")
translations
"[x<-xs . P]"== "CONST filter (%x. P) xs"
and indeed term "filter (λ x. ¬(P x)) l" will nicely print
"[x←l . ¬ P x]" :: "int list"
But if the expression is simple, e.g. ilter (λ x. P x) l, eta-contraction seems to happen and I get shown
"filter P l" :: "int list"
Can I somehow force the nice syntax (i.e. [x←l . P x]) here as well?
You can avoid eta-contraction by installing an appropriate print_translation. There are several examples for binders and tuples in the HOL sources, e.g., for THE in HOL.thy. They are easy to adapt to filter, for example:
print_translation {*
[(#{const_syntax filter}, fn _ => fn [Abs abs, xs] =>
let val (x, t) = Syntax_Trans.atomic_abs_tr' abs
in Syntax.const #{syntax_const "_filter"} $ x $ t $ xs end)]
*} -- {* To avoid eta-contraction of body *}

Resources