[isabelle-dev] I'd like to better understand some operations from Local_Theory.

2011-04-07 Thread Thomas Sewell
Hello Isabelle developers.

I'm doing an experiment in which I need to programmatically construct a locale. 
For simplicity I used the same operations that Michael Norrish was using in the 
l4.verified C code parser, Local_Theory.define and Local_Theory.notes. This led 
to some strange behaviour.

Suppose I set up ML actions for adding a definition foo = True to a locale 
and for getting the constant named foo

locale test = assumes True
begin

ML {*
val add_foo = Local_Theory.define ((@{binding foo}, NoSyn), 
(Attrib.empty_binding, @{term True}))
  # snd;
fun get_foo ctxt = ProofContext.read_const ctxt false dummyT foo;
*}
ML {*
val ctxt = @{context};
*}

If I run the add_foo operation with local_setup, get_foo tells me foo is now 
the constant local.foo.

local_setup {* add_foo *}
ML {* get_foo @{context} *}

This looked promising for my experiment. However, performing these actions 
within a single ML block tells me foo is extracted by read_const as the free 
variable foo (with the correct type).

ML {* get_foo (add_foo ctxt) *}

That had me stumped for hours. It turns I can get the behaviour I want with 
judicious interspersing of Local_Theory.restore.

ML {* get_foo (Local_Theory.restore (add_foo ctxt)) *}

However I'm just reciting incantations at this point. Furthermore I had no idea 
where to go looking for this incantation other than to try a collection of 
uncommented functions from Local_Theory. I've been a bit negligent about 
reading the various manuals that have cropped up of late; would any of them 
have explained what is going on?

Also, the behaviour if one supplies a functional pattern to local_setup has to 
be seen to be believed:

local_setup {* fn _ = add_foo ctxt *}
ML {* get_foo @{context} *}
ML {* get_foo ctxt *}

Although in writing this email I finally understood: the context saved in 
@{context} when ctxt was being defined includes the local ML interpreter state, 
which is one in which ctxt isn't defined yet. I guess that's what I get for 
playing with setup/local_setup.

I'll rephrase my question: should I have been better informed about this, or 
are local definitions genuinely inscrutable?

Yours,
Thomas.

The information in this e-mail may be confidential and subject to legal 
professional privilege and/or copyright. National ICT Australia Limited accepts 
no liability for any damage caused by this email or its attachments.
___
isabelle-dev mailing list
isabelle-...@in.tum.de
https://mailmanbroy.informatik.tu-muenchen.de/mailman/listinfo/isabelle-dev


Re: [isabelle-dev] I'd like to better understand some operations from Local_Theory.

2011-04-07 Thread Makarius

On Thu, 7 Apr 2011, Thomas Sewell wrote:

Suppose I set up ML actions for adding a definition foo = True to a 
locale and for getting the constant named foo


locale test = assumes True
begin

ML {*
val add_foo = Local_Theory.define ((@{binding foo}, NoSyn), 
(Attrib.empty_binding, @{term True}))
 # snd;
fun get_foo ctxt = ProofContext.read_const ctxt false dummyT foo;
*}
ML {*
val ctxt = @{context};
*}

If I run the add_foo operation with local_setup, get_foo tells me foo 
is now the constant local.foo.


local_setup {* add_foo *}
ML {* get_foo @{context} *}


Looks fine so far, although ProofContext.read_const is a bit unusual.  I 
had to do a hypersearch on the whole sources myself to get an idea of what 
is its point.  A quick glance at its typicaly uses confirms its exotic 
nature. Plain Syntax.read_term should do the job in most situations.



However, performing these actions within a single ML block tells me 
foo is extracted by read_const as the free variable foo (with the 
correct type).


ML {* get_foo (add_foo ctxt) *}

That had me stumped for hours.


You could have spend the time studying chapter 7 in the implementation 
manual and the two papers being cited there.


What you have encountered here is the hypothetical entity within the 
auxiliary context of the local theory target.  These are very important 
concepts.  Thus the details of the actual target mechanisms are hidden 
from a definitional package, i.e. it will work uniformly for global 
theories, locales, type classes etc.



It turns I can get the behaviour I want with judicious interspersing of 
Local_Theory.restore.


ML {* get_foo (Local_Theory.restore (add_foo ctxt)) *}


Thus you pretend to be on a package boundary. Normally you don't want 
this, although there are rare situations where there is no better 
workaround.  Again a hypersearch on the sources reveals that 
Local_Theory.restore is hardly ever used in practice.


It is important to read the sources the proper way.


Also, the behaviour if one supplies a functional pattern to local_setup 
has to be seen to be believed:


local_setup {* fn _ = add_foo ctxt *}
ML {* get_foo @{context} *}
ML {* get_foo ctxt *}

Although in writing this email I finally understood: the context saved 
in @{context} when ctxt was being defined includes the local ML 
interpreter state, which is one in which ctxt isn't defined yet. I guess 
that's what I get for playing with setup/local_setup.


As usual when there is a surprise there are two main possibilities:

  (1) unexpectedly general types being inferred for some terms
  (2) working with an unexpected context

The local setup above ignores the current context and returns to an update 
of an earlier one.  There should be no surprise that the ML toplevel 
environment is part of the context -- everything in Isabelle is part of 
the context.  (There are a few corner cases where this rule is violated, 
and these should be the surprising ones.)


BTW, Poly/ML is a native code compiler, not an interpreter.

BTW2, the Poly/ML runtime state is *not* saved, i.e. mutable content is 
not subject to the context.  Since mutable content is hardly ever used 
these days, one can mostly forget about it.



Makarius
___
isabelle-dev mailing list
isabelle-...@in.tum.de
https://mailmanbroy.informatik.tu-muenchen.de/mailman/listinfo/isabelle-dev