Access a definition from a locale - isabelle

Specific example: Let's say I have demonstrated that I have a graph in the sense of https://www.isa-afp.org/theories/category3/#FreeCategory.html :
lemma i_have_a_graph: shows "graph Obj Arr Dom Cod"
sorry
where the symbols Obj, Arr, Dom, and Cod were defined earlier in the file. This gives me access to the lemmas and theorems stated within the graph locale.
How do I use the symbol path defined within the graph locale?
Related question with no answers: Access definitions from sublocale

You don't do it using a lemma but by the interpretation command:
interpretation MyGraph: graph Obj Are Dom Cod <proof>
Of course, the <proof> could use your lemma, but you don't need to prove such a lemma separately.
Now MyGraph.path refers to the path component of this instance.
See https://www.cl.cam.ac.uk/research/hvg/Isabelle/dist/Isabelle/doc/locales.pdf

Related

Isabelle tactic definition

I was trying to copy a tactic file that might help proving my theorem, however, there seems to be having some problems.
The original tactic is like this:
fun typechk_step_tac tyrls =
FIRSTGOAL (test_assume_tac ORELSE' filt_resolve_tac tyrls 4);
(* Output:
Value or constructor (filt_resolve_tac) has not been declared
*)
I tried to find this tactic in the internet, but there is not much explanation of this. I saw that some theory file in 2009 use this method, and for 2020 one, a theory file use a similar method called filt_resolve_from_net_tac, which I think the types of them are different, so I am not sure about how to use them.
Other than the filt_resolve_tac, the tactic file used a function called ref like this:
val basictypeinfo = ref([]:thm list);
(* Output:
Value or constructor (ref) has not been declared
*)
However, the Isabelle 2020 seems know something about the ref, since when I changed something:
val basictypeinfo = [];
fun addT typelist = (basictypeinfo := (typelist #(!basictypeinfo)));
(* It shows error:
Type error in function application.
Function: ! : 'a ref -> 'a
Argument: basictypeinfo : 'a list
Reason: Can't unify 'a ref (*In Basis*) with 'a list (*In Basis*) (Different type constructors)
*)
It clearly shows that ref is like a type, and it is defined in the Isabelle right?
Therefore the ref in ref([]:the list) should be similar to a casting function, and I found that there is a thing called Unsynchronized.ref which solves the type problem, may I know are they the same thing in this context?
In the later part of the files, there are also some tactic and rule set seems to be not defined, for example:
etac: Value or constructor (etac) has not been declared
(*
I saw Prof. Paulson had shown this tactic in his Isabelle lecture,
but I couldn't find it in the Isabelle manual or the implementation manual,
is the name of it changed?
*)
ZF_typechecks: I couldn't find any rule sets that has this name in the whole ZF directory.
Sorry to have so many questions, it seems that the tactic file is no longer really well-supported by the new Isabelle, are there still people using Isar/ML to define new tactic? Or most people are doing this with the method declaration in the Isabelle? And which part of the Isabelle/Isar reference manual should I read to master this skill? Thank you very much indeed.

quotient_type warning "no map function"

When using the quotient_type command I get the following warning: "No map function defined for Example.A. This will cause problems later on".
Here is a minimal example to trigger the warning(tested with Isabelle2017).
theory Example
imports
Main
begin
datatype 'a A = B "'a A" | C
(*for map: map *) (* uncommenting doesn't fix the warning*)
quotient_type 'a Q = "'a A" / "op ="
by (rule identity_equivp)
end
So my questions are:
What is meant by a map function in this context (I only do know the concept of a map function in the context of functors in functional programming)?
What does it have to do with the datatype packages map functions, like one that would be generated by the commented line?
Which problems will one get later on?
The datatype command does not by default register the generated map function with the quotient package because there may be more general mappers (in case there are dead type variables). You therefore must do the functor declaration manually:
functor map_A
by(simp_all add: A.map_id0 A.map_comp o_def)
The mapper and its theorems are needed if you later want to lift definitions through the quotient type. This has been discussed on the Isabelle mailing list.

Print/query class instances in Isabelle

I am just getting started with Isabelle. I have a file like this:
theory Z
imports Main Int
begin
value "(2::int) + (2::int)"
lemma "(n::int) + (m::int) = m + n"
apply(auto) done
print_locale comm_ring_1
print_interps comm_ring_1
end
Most of this works as I expected: Isabelle tells me that 2+2=4, and it knows how to prove that n+m=m+n, and it prints the axioms for a commutative unital ring.
However, I expected that the line "print_interps comm_ring_1" would cause Isabelle to tell me that it knows that the integers are an instance of the class comm_ring_1 (given that this fact is certainly proved in the file Int.thy in the standard library, which we have imported). But Isabelle does not in fact tell me that.
Is there some other way to ask Isabelle to list all the instances of comm_ring_1 that it knows about? Or to query specifically whether int is an instance of comm_ring_1? I have looked in the reference manual for such a command, but cannot find one.
Every type class in Isabelle defines a locale of the same name, but they are not the same. The commands print_locale and print_interps consider only the locale aspect of a type class. Type class registration with instance or instantiation does not register the type as an interpretation of that locale. Therefore print_interps does not list the types that have been proven instances of type classes. This is done by the command print_classes.

Using syntax/translations wiith locales

Is there any known hack that allows custom syntax for definitions inside a given locale, using the syntax/translation mechanism? All of my attempts at an "obvious" solution are generating type errors, which I am led to believe is caused by syntax/translation not yet being made "locale-aware".
Raw AST transformations with syntax and translations cannot be used inside locales in Isabelle2016. There is a workaround for constants and types whose declaration does not depend on locale parameters. You merely have to issue the syntax declaration outside of the locale for the appropriate constant from background theory. Below is a proof of concept:
locale test = fixes a :: nat begin
definition foo :: "nat ⇒ nat" where "foo x = x"
end
syntax "_foo" :: "nat ⇒ bool" ("FOO")
translations "FOO" ↽ "CONST test.foo"
context test begin
term foo
This workaround does not work for constants which depend on parameters of the locale, because then constant in the background theory takes these parameters as additional arguments and the locale installs an abbreviation, which is folded before the custom syntax translation fires.

How can I pass a ML value as an argument to an outer syntax command?

I define an outer syntax command, imake to write some code to a file and do some other things. The intended usage is as follows:
theory Scratch
imports Complex_Main "~/Is0/IsS"
begin
imake ‹myfile›
end
The above example will write some contents to the file myfile. myfile should be a path relative to the location of the Scratch theory.
ML ‹val this_path = File.platform_path(Resources.master_directory #{theory})
I would like to be able to use the value this_path in specifying myfile. The imake command is defined in the import ~/Is0/IsS and currently looks as follows:
ML‹(*imake*)
val _ = Outer_Syntax.improper_command #{command_spec "imake"} ""
(Parse.text >>
(fn path => Toplevel.keep
(fn _ => Gc.imake path)))›
The argument is pased using Parse.text, but I need feed it the path based on the ML value this_path, which is defined later (in the Scratch theory). I searched around a lot, trying to figure out how to use something like Parse.const, but I won't be able to figure anything out any time soon.
So: It's important that I use, in some way, Resources.master_directory #{theory} in Scratch.thy, so that imake gets the folder Scratch is in, which will come from the use of #{theory} in Scratch.
If I'm belaboring the last point, it's because in the past, I wasted a lot of time getting the wrong folder, because I didn't understand how to use the command above correctly.
How can I achieve this?
Your minimal examples uses Resource.master_directory with the parameter #{theory} to define your path. #{theory} refers (statically) to the theory at the point where you write down the antiquotation. This is mostly for interactive use, when you explore stuff. For code which is used in other places, you must use the dynamically passed context and extract the theory from it.
The function Toplevel.keep you use takes a function Toplevel.state -> unit as an argument. The Toplevel.state contains a context (see chapter 1 of the Isabelle Implementation Manual), which again contains the current theory; with Toplevel.theory_of you can extract the theory from the state. For example, you could use
Toplevel.keep (fn state => writeln
(File.platform_path (Resources.master_directory (Toplevel.theory_of state))))
to define a command that prints the master_directory for your current theory.
Except in simple cases, it is very likely that you do not only need the theory, but the whole context (which you can get with Toplevel.context_of).
Use setup from preceding (parts of the) theory
In the previous section, I assumed that you always want to use the master directory. For the case where the path should be configurable, Isabelle knows the concept of configuration options.
In your case, you would need to define an configuration option before you declare your imake command
ML ‹
val imake_path = Attrib.setup_config_string #{binding imake_path}
(K path)
› (* declares an option imake_path with the value `path` as default value *)
Then, the imake command can refer to this attribute to retrieve the path via Config.get:
Toplevel.keep (fn state =>
let val path = Config.get (Toplevel.context_of state) imake_path
in ... end)
The value of imake_path can then be set in Isar (only as a string):
declare [[imake_path="/tmp"]]
or in ML, via Config.map (for updating proof contexts) or Config.map_global (for updating theories). Note that you need to feed the updated context back to the system. Isar has the command setup (takes an ML expression of type theory -> theory) for that:
setup ‹Config.map_global imake_path (K "/tmp")›
Configuration options are described in detail in the Isar Implementation Manual, section 1.1.5.
Note: This mechanism does not allow you to automatically set imake_path to the master directory for each new theory. You need to set it manually, e.g. by adding
setup ‹
Config.map imake_path
(K (File.platform_path (Resources.master_directory #{theory})))
›
at the beginning of each theory.
The more general mechanism behind configuration options is context data. For details, see section 1.1 and in particular section 1.1.4 of the Isabelle Implementation Manual). This mechanism is used in a lot of places in Isabelle; the simpset, the configuration of the simplifier, is one example for this.

Resources