Packages

class Isabelle extends AnyRef

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. AnyRef
  3. Any
  1. Hide All
  2. Show All
Visibility
  1. Public
  2. Protected

Instance Constructors

  1. new Isabelle(setup: Setup, build: Boolean = true)

    setup

    Configuration object that specifies the path of the Isabelle binary etc. See de.unruh.isabelle.control.Isabelle.Setup. This also specifies with Isabelle heap to load.

    build

    Whether to build the Isabelle heap before running Isabelle. If false, the heap will never be built. (This means changes in the Isabelle theories will not be reflected. And if the heap was never built, the Isabelle process fails.) If true, the Isabelle build command will be invoked. That command automatically checks for changed dependencies but may add a noticable delay even if the heap was already built.

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 clone(): AnyRef
    Attributes
    protected[lang]
    Definition Classes
    AnyRef
    Annotations
    @throws(classOf[java.lang.CloneNotSupportedException]) @native() @HotSpotIntrinsicCandidate()
  8. 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.

  9. final def eq(arg0: AnyRef): Boolean
    Definition Classes
    AnyRef
  10. def equals(arg0: AnyRef): Boolean
    Definition Classes
    AnyRef → Any
  11. 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.)

  12. def executeMLCodeNow(ml: String): Unit

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

  13. final def getClass(): Class[_ <: AnyRef]
    Definition Classes
    AnyRef → Any
    Annotations
    @native() @HotSpotIntrinsicCandidate()
  14. def hashCode(): Int
    Definition Classes
    AnyRef → Any
    Annotations
    @native() @HotSpotIntrinsicCandidate()
  15. def isDestroyed: Boolean

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

  16. final def isInstanceOf[T0]: Boolean
    Definition Classes
    Any
  17. final def ne(arg0: AnyRef): Boolean
    Definition Classes
    AnyRef
  18. final def notify(): Unit
    Definition Classes
    AnyRef
    Annotations
    @native() @HotSpotIntrinsicCandidate()
  19. final def notifyAll(): Unit
    Definition Classes
    AnyRef
    Annotations
    @native() @HotSpotIntrinsicCandidate()
  20. val setup: Setup
  21. 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.)

  22. final def synchronized[T0](arg0: => T0): T0
    Definition Classes
    AnyRef
  23. def toString(): String
    Definition Classes
    AnyRef → Any
  24. final def wait(arg0: Long, arg1: Int): Unit
    Definition Classes
    AnyRef
    Annotations
    @throws(classOf[java.lang.InterruptedException])
  25. final def wait(arg0: Long): Unit
    Definition Classes
    AnyRef
    Annotations
    @throws(classOf[java.lang.InterruptedException]) @native()
  26. 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 AnyRef

Inherited from Any

Ungrouped