class Isabelle extends FutureValue
A running instance of Isabelle.
The Isabelle process is initialized with some ML code that allows this class to remote control Isabelle. In more detail:
The Isabelle process maintains a map from IDs to values (the "object store"). Those values can be of any type (e.g., integers, terms, functions, etc.). (How this works in a strongly typed language such as ML is described below.) The Isabelle class has functions to operate on the values in the object store (e.g., creating new objects, retrieving the value of an object, performing operations on objects).
The operations provided by this class are very lowlevel. For more convenient and type-safe operations on values in the object store, see de.unruh.isabelle.mlvalue.MLValue.
Operations on objects are asynchronous and return futures.
On the Scala side, the IDs of objects are represented by the class de.unruh.isabelle.control.Isabelle.ID. These IDs ensure garbage collection – if an ID is not referenced any more on the Scala side, it will be removed from the object store in the Isabelle process, too.
To be able to store objects of different types in the object store, even though ML does not support subtyping,
we make use of the fact that all exceptions share the same ML type exn. The object store stores only values of
type exn. To store, e.g., integers, we define an exception exception E_Int of int. Then for an integer i,
E_Int i is an exception that can be stored in the object store. We can convert the exception back to an integer
using the function fn E_Int i => i that uses pattern matching. (This will raise Match if the given exception is
does not contain an integer. This way we achieve dynamic typing of our object store.) The following exceptions are
predefined in structure Control_Isabelle:
exception E_Function of exn -> exn exception E_Int of int exception E_String of string exception E_Pair of exn * exn
(That structure also exports functions store and handleLines which are for internal use only
and must not be used in the ML code.)
Note that some of the exception again refer to the exn type, e.g., E_Pair. Thus, to store a pair of integers,
we use the term E_Pair (E_Int 1, E_Int 2).
New exceptions for storing other types can be defined at runtime using executeMLCode.
- Source
- Isabelle.scala
- Alphabetic
- By Inheritance
- Isabelle
- FutureValue
- AnyRef
- Any
- Hide All
- Show All
- Public
- All
Instance Constructors
-
new
Isabelle(setup: SetupGeneral)
The constructor initialize the Isabelle instance partly asynchronously.
The constructor initialize the Isabelle instance partly asynchronously. That is, when the constructor returns successfully, it is not guaranteed that the Isabelle process was initialized successfully. To check and wait for successful initialization, use the methods from FutureValue (supertrait of this class), e.g.,
new Isabelle(...).force.- setup
Configuration object that specifies the path of the Isabelle binary etc. See de.unruh.isabelle.control.Isabelle.SetupGeneral. This also specifies with Isabelle heap to load.
Value Members
-
final
def
!=(arg0: Any): Boolean
- Definition Classes
- AnyRef → Any
-
final
def
##(): Int
- Definition Classes
- AnyRef → Any
-
final
def
==(arg0: Any): Boolean
- Definition Classes
- AnyRef → Any
-
def
applyFunction(f: Future[ID], x: Data)(implicit ec: ExecutionContext): Future[Data]
Like applyFunction(ID,Data), except
fis a future. -
def
applyFunction(f: ID, x: Data): Future[Data]
Applies
ftoxand returns the result.Applies
ftoxand returns the result.fmust be the ID of an object in the object store of the formE_Function f'(and thusf'of ML typedata -> data).xis serialized and transferred to the Isabelle process, the valuef' xis computed, serialized and transferred back.By definition of the type Isabelle.Data,
xcan be a tree containing integers, strings, and object IDs. When transferring an object ID to the Isabelle process, it is replaced by the object (exception) that is referred by the ID. And similarly, objects (exceptions) in the return value are added to the object store and replaced by IDs upon transfer to the Scala side.This behavior gives rise to two simple use patterns:
Retrieving values: Say
treeis some algebraic data type on the ML side,Treeis a corresponding Scala class,encode : tree -> datais a function that encodes a tree asdata(using the DList, DInt, and DString constructors only), andE_Tree of treeis an exception type to store trees in the object store. Then we can define a function for retrieving a tree from the object store to Scala as follows:val encodeID : Future[ID] = isabelle.storeValue("fn DObject (E_Tree tree) => encode tree") def decode(data: Data) : Tree = ??? // The opposite of the ML function encode def retrieve(id: ID) : Tree = { // Apply encode to the element referenced by id, result is an encoding of the tree as Data val dataFuture : Future[Data] = isabelle.applyFunction(encodeID, DObject(id)) // For simplicitly, we force synchronous execution val data : Data = Await.result(dataFuture, Duration.Inf) decode(data) }
Storing values: Continuing the above example, say
decode : data -> treeis an ML function that decodes trees (inverse ofencodeabove). Then we can store trees in the object store from Scala using the following functionstore:val decodeID : Future[ID] = isabelle.storeValue("fn data => DObject (E_Tree (decode data))") def encode(tree: Tree) : Data = ??? // The opposite of the ML function decode def store(tree: Tree) : ID = { // Apply ML-decode to the Scala-encoded tree, store it in the object store, and return the ID (inside a Data) val dataFuture : Future[Data] = isabelle.applyFunction(decodeID, encode(tree)) // For simplicitly, we force synchronous execution val data : Data = Await.result(dataFuture, Duration.Inf) // get the ID inside the returned data (referring to the tree object in the object store) val DObject(id) = data id }
Of course, arbitrary combinations of these two ideas are possible. For example, one could have a Scala data structure that contains IDs of objects still on the ML side. These data structures can be serialized and deserialized similar to the above example, using the fact that the type Isabelle.Data allows IDs to occur anywhere in the tree.
Objects added to the object store by this mechanism are garbage collected on the ML side when the corresponding IDs are not used any more on the Scala side.
This approach is very low level. In particular, there is no type system support to ensure that the IDs contained in the serialized data actually refer to objects of the right type. A higher level typesafe approach for accessing data in the object store is given by de.unruh.isabelle.mlvalue.MLValue (see there). However,
MLValues internally use the mechanism described here to transfer data to/from the Isabelle process. Thus, to add support forMLValues of new types, theapplyFunctionneeds to be used.- returns
A future holding the ID of the result (or holding an exception if the
fis notE_Function f'orf' xthrows an exception in ML)
- See also
Isabelle.Data for information what kind of data can be contained in
xand the result
-
final
def
asInstanceOf[T0]: T0
- Definition Classes
- Any
-
def
await: Unit
Blocks until this future value is computed.
Blocks until this future value is computed. (Or throws an exception if the computation fails.)
- Definition Classes
- Isabelle → FutureValue
-
def
checkDestroyed(): Unit
Throws an IsabelleDestroyedException if this Isabelle process has been destroyed.
Throws an IsabelleDestroyedException if this Isabelle process has been destroyed. Otherwise does nothing.
- Annotations
- @throws( "if the process was destroyed" )
-
def
clone(): AnyRef
- Attributes
- protected[lang]
- Definition Classes
- AnyRef
- Annotations
- @throws( ... ) @native() @HotSpotIntrinsicCandidate()
-
def
destroy(): Unit
Kills the running Isabelle process.
Kills the running Isabelle process. After this, no more operations on values in the object store are possible. Futures corresponding to already running computations will throw an IsabelleDestroyedException.
-
final
def
eq(arg0: AnyRef): Boolean
- Definition Classes
- AnyRef
-
def
equals(arg0: Any): Boolean
- Definition Classes
- AnyRef → Any
-
val
exceptionManager: ExceptionManager
ExceptionManager instance that handles exception creation in this Isabelle instance.
-
def
executeMLCode(ml: String): Future[Unit]
Executes the ML code
mlin the Isabelle process.Executes the ML code
mlin the Isabelle process.WARNING: This has a global side effect on the current Isabelle process because it modifies the ML name space.
Definitions made in
mlaffect the ML name space. (This name space is shared by all invocations of executeMLCode and storeValue.) This is intended mostly for defining new types. To create values (e.g., ifmlis the code of a function that should be executed), preferably use storeValue which creates anonymous values in the object store. The ML code is executed in a context where the structureControl_Isabelleis not opened (i.e., you have to writeControl_Isabelle.E_Intinstead ofE_Int).Example:
executeMLCode("exception E_Term of term")would declare an exception to store terms. (Not actually needed because this specific exception is predeclared.)- returns
A future that completes when the code was executed. (Or throws an IsabelleControllerException if the ML code compilation/execution fails.)
-
def
executeMLCodeNow(ml: String): Unit
Like executeMLCode but waits for the code to be executed before returning.
-
def
force: Isabelle.this.type
Waits till the computation of this value (in the Isabelle process) has finished.
Waits till the computation of this value (in the Isabelle process) has finished. (Or until an exception is thrown.)
- returns
this value, but it is guaranteed to have completed the computation
- Definition Classes
- FutureValue
-
def
forceFuture(implicit ec: ExecutionContext): Future[Isabelle.this.type]
A future containing this object with the computation completed.
A future containing this object with the computation completed. In particular, if this value throws an exception upon computation, the future holds that exception.
- Definition Classes
- FutureValue
-
final
def
getClass(): Class[_]
- Definition Classes
- AnyRef → Any
- Annotations
- @native() @HotSpotIntrinsicCandidate()
-
def
hashCode(): Int
- Definition Classes
- AnyRef → Any
- Annotations
- @native() @HotSpotIntrinsicCandidate()
-
def
isDestroyed: Boolean
Returns whether the Isabelle process has been destroyed (via destroy)
-
final
def
isInstanceOf[T0]: Boolean
- Definition Classes
- Any
-
final
def
ne(arg0: AnyRef): Boolean
- Definition Classes
- AnyRef
-
final
def
notify(): Unit
- Definition Classes
- AnyRef
- Annotations
- @native() @HotSpotIntrinsicCandidate()
-
final
def
notifyAll(): Unit
- Definition Classes
- AnyRef
- Annotations
- @native() @HotSpotIntrinsicCandidate()
- val setup: SetupGeneral
-
def
someFuture: Future[Unit]
Returns a future that completes when the computation of this object is complete.
Returns a future that completes when the computation of this object is complete. (Or that holds an exception if that computation throws an exception.) However, upon successful completion, the future may return an arbitrary (and thus useless) value. May be faster to implement than forceFuture because there may be already a future available but that returns the wrong value.
- Definition Classes
- Isabelle → FutureValue
-
def
stateString: String
A utility method that returns "" if this value was successfully computed, " (computing)" if it still computes, and " (failed)" if it finished with an exception.
A utility method that returns "" if this value was successfully computed, " (computing)" if it still computes, and " (failed)" if it finished with an exception.
This can be useful to constructing human readable messages about this value.
- Definition Classes
- FutureValue
-
def
storeValue(ml: String): Future[ID]
Executes the ML expression
mlin the Isabelle process.Executes the ML expression
mlin the Isabelle process.The expression must be of ML type
exn. The result of evaluating the expression is added to the object store. The ML code is executed in a context where the structureControl_Isabelleis opened (i.e., you can writeE_Intinstead ofControl_Isabelle.E_Int).In code that is supposed to support multiple instances of Isabelle, it can be cumbersome to keep track in which instances a given ML code fragment was already executed. See OperationCollection for a helper class to facilitate that.
- returns
Future that contains an ID referencing the result in the object store. (Or throws an IsabelleControllerException if the ML code compilation/execution fails.)
-
final
def
synchronized[T0](arg0: ⇒ T0): T0
- Definition Classes
- AnyRef
-
def
toString(): String
- Definition Classes
- AnyRef → Any
-
final
def
wait(arg0: Long, arg1: Int): Unit
- Definition Classes
- AnyRef
- Annotations
- @throws( ... )
-
final
def
wait(arg0: Long): Unit
- Definition Classes
- AnyRef
- Annotations
- @throws( ... ) @native()
-
final
def
wait(): Unit
- Definition Classes
- AnyRef
- Annotations
- @throws( ... )