Packages

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
Linear Supertypes
Ordering
  1. Alphabetic
  2. By Inheritance
Inherited
  1. Isabelle
  2. FutureValue
  3. AnyRef
  4. Any
  1. Hide All
  2. Show All
Visibility
  1. Public
  2. Protected

Instance Constructors

  1. 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

  1. final def !=(arg0: Any): Boolean
    Definition Classes
    AnyRef → Any
  2. final def ##: Int
    Definition Classes
    AnyRef → Any
  3. final def ==(arg0: Any): Boolean
    Definition Classes
    AnyRef → Any
  4. def applyFunction(f: Future[ID], x: Data)(implicit ec: ExecutionContext): Future[Data]

    Like applyFunction(ID,Data), except f is a future.

  5. def applyFunction(f: ID, x: Data): Future[Data]

    Applies f to x and returns the result.

    Applies f to x and returns the result.

    f must be the ID of an object in the object store of the form E_Function f' (and thus f' of ML type data -> data).

    x is serialized and transferred to the Isabelle process, the value f' x is computed, serialized and transferred back.

    By definition of the type Isabelle.Data, x can 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 tree is some algebraic data type on the ML side, Tree is a corresponding Scala class, encode : tree -> data is a function that encodes a tree as data (using the DList, DInt, and DString constructors only), and E_Tree of tree is 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 -> tree is an ML function that decodes trees (inverse of encode above). Then we can store trees in the object store from Scala using the following function store:

    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 for MLValues of new types, the applyFunction needs to be used.

    returns

    A future holding the ID of the result (or holding an exception if the f is not E_Function f' or f' x throws an exception in ML)

    See also

    Isabelle.Data for information what kind of data can be contained in x and the result

  6. final def asInstanceOf[T0]: T0
    Definition Classes
    Any
  7. 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
    IsabelleFutureValue
  8. 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")
  9. def clone(): AnyRef
    Attributes
    protected[lang]
    Definition Classes
    AnyRef
    Annotations
    @throws(classOf[java.lang.CloneNotSupportedException]) @native() @HotSpotIntrinsicCandidate()
  10. 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.

  11. final def eq(arg0: AnyRef): Boolean
    Definition Classes
    AnyRef
  12. def equals(arg0: AnyRef): Boolean
    Definition Classes
    AnyRef → Any
  13. def executeMLCode(ml: String): Future[Unit]

    Executes the ML code ml in the Isabelle process.

    Executes the ML code ml in the Isabelle process.

    WARNING: This has a global effect on the Isabelle process because it modifies the ML name space.

    Definitions made in ml affect the global Isabelle name space. This is intended mostly for defining new types. To create values (e.g., if ml is 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 structure Control_Isabelle is not opened (i.e., you have to write Control_Isabelle.E_Int instead of E_Int).

    returns

    A future that completes when the code was executed. (Or throws an IsabelleControllerException if the ML code compilation/execution fails.)

  14. def executeMLCodeNow(ml: String): Unit

    Like executeMLCode but waits for the code to be executed before returning.

  15. 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
  16. 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.

    Roughly the same as Future { this.force }.

    Definition Classes
    FutureValue
  17. final def getClass(): Class[_ <: AnyRef]
    Definition Classes
    AnyRef → Any
    Annotations
    @native() @HotSpotIntrinsicCandidate()
  18. def hashCode(): Int
    Definition Classes
    AnyRef → Any
    Annotations
    @native() @HotSpotIntrinsicCandidate()
  19. def isDestroyed: Boolean

    Returns whether the Isabelle process has been destroyed (via destroy)

  20. final def isInstanceOf[T0]: Boolean
    Definition Classes
    Any
  21. final def ne(arg0: AnyRef): Boolean
    Definition Classes
    AnyRef
  22. final def notify(): Unit
    Definition Classes
    AnyRef
    Annotations
    @native() @HotSpotIntrinsicCandidate()
  23. final def notifyAll(): Unit
    Definition Classes
    AnyRef
    Annotations
    @native() @HotSpotIntrinsicCandidate()
  24. val setup: SetupGeneral
  25. 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
    IsabelleFutureValue
  26. 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
  27. def storeValue(ml: String): Future[ID]

    Executes the ML expression ml in the Isabelle process.

    Executes the ML expression ml in the Isabelle process.

    WARNING: This has a global effect on the Isabelle process because it modifies the ML name space.

    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 structure Control_Isabelle is opened (i.e., you can write E_Int instead of Control_Isabelle.E_Int).

    Example: storeValue("exception E_Term of term") (this is actually done by de.unruh.isabelle.pure.Term).

    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.)

  28. final def synchronized[T0](arg0: => T0): T0
    Definition Classes
    AnyRef
  29. def toString(): String
    Definition Classes
    AnyRef → Any
  30. final def wait(arg0: Long, arg1: Int): Unit
    Definition Classes
    AnyRef
    Annotations
    @throws(classOf[java.lang.InterruptedException])
  31. final def wait(arg0: Long): Unit
    Definition Classes
    AnyRef
    Annotations
    @throws(classOf[java.lang.InterruptedException]) @native()
  32. final def wait(): Unit
    Definition Classes
    AnyRef
    Annotations
    @throws(classOf[java.lang.InterruptedException])

Deprecated Value Members

  1. def finalize(): Unit
    Attributes
    protected[lang]
    Definition Classes
    AnyRef
    Annotations
    @throws(classOf[java.lang.Throwable]) @Deprecated
    Deprecated

Inherited from FutureValue

Inherited from AnyRef

Inherited from Any

Ungrouped