问题
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?
回答1:
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.
来源:https://stackoverflow.com/questions/25841823/how-can-i-pass-a-ml-value-as-an-argument-to-an-outer-syntax-command