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

假装没事ソ 提交于 2019-12-24 00:58:17

问题


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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!