Packages

class MLValue[A] extends FutureValue

A type safe wrapper for values stored in the Isabelle process managed by Isabelle.

As explained in the documentation of Isabelle, the Isabelle process has an object store of values, and the class Isabelle.ID is a reference to an object in that object store. However, values of different types share the same object store. Thus Isabelle.ID is not type safe: there are compile time guarantees that the value referenced by that ID has a specific type.

MLValue[A] is a thin wrapper around an ID id (more precisely, a future holding an ID). It is guaranteed that id references a value in the Isabelle process of an ML type corresponding to A (or throw an exception). (It is possible to violate this guarantee by type-casting the MLValue though.) For supported types A, it is possible to automatically translate a Scala value x of type A into an MLValue[A] (which behind the scenes means that x is transferred to the Isabelle process and added to the object store) and also to automatically translate an MLValue[A] back to a Scala value of type A. Supported types are Int, Long, Boolean, Unit, String, and lists and tuples (max. 7 elements) of supported types. (It is also possible for A to be the type MLValue[...], see MLValueConverter for explanations.) It is possible to add support for other types, see MLValue.Converter for instructions. Using this mechanism, support for the terms, types, theories, contexts, and theorems has been added in package de.unruh.isabelle.pure.

In more detail:

  • For any supported Scala type A there should be a unique corresponding ML type a. (This is not enforced if we add support for new types, but if we violate this, we loose type safety.)
  • Several Scala types A are allowed to correspond to the same ML type a. (E.g., both Long and Int correspond to the unbounded int in ML.)
  • For each supported type A, the following must be specified (via an implicit MLValue.Converter):
    • an encoding of a as an exception (to be able to store it in the object store)
    • ML functions to translate between a and exceptions and back
    • retrieve function: how to retrieve an exception encoding an ML value of type a and translate it into an A in Scala
    • store function: how to translate an A in Scala into an an exception encoding an ML value of type a and store it in the object store.
  • MLValue(x) automatically translates x:A into a value of type a (using the retrieve function) and returns an MLValue[A].
  • If m : MLValue[A], then m.retrieve (asynchronous) and m.retrieveNow (synchronous) decode the ML value in the object store and return a Scala value of type A.
  • ML code that operates on values in the Isabelle process can be specified using MLValue.compileValue and MLValue.compileFunction[D,R]*. This ML code directly operates on the corresponding ML type a and does not need to consider the encoding of ML values as exceptions or how ML types are serialized to be transferred to Scala (all this is handled automatically behind the scenes using the information provided by the implicit MLValue.Converter).
  • To be able to use the automatic conversions etc., converters need to be imported for supported types. The converters provided by this package can be imported by import de.unruh.isabelle.mlvalue.Implicits._.
  • MLValues are asynchronous, i.e., they may finish the computation of the contained value after creation of the MLValue object. (Like a Future.) In particular, exception thrown during the computation are not thrown during object creation. The value inside an MLValue can be retrieved using retrieveNow (or retrieve), this may wait for the computation to finish and force the exceptions to be thrown. However, instead the value returned by retrieveNow may also be an asynchronous value in the sense that it is created before the computation defining it has finished. Thus exceptions thrown in the computation of the MLValue may be delayed even further and only show upon later computations with the returned object. To make sure that the computation of the MLValue has completed, use the methods of FutureValue (which MLValue inherits), such as force.
  • We have the convention that if A is not a subtype of FutureValue, then retrieveNow must throw the exceptions raised during the computation of the MLValue, and retrieve must return a future that holds those exceptions. (That is, in this case the considerations of the preceding bullet point do not apply.) For example, if MLValue[Unit].retrieveNow or MLValue[Int].retrieveNow guarantee that all exceptions are thrown (i.e., if those function calls complete without exception, the underlying computation is guaranteed to be have completed without exception). If MLValue[Term].retrieveNow completes without exception, this is not guaranteed (because Term is a subtype of FutureValue). But MLValue[Term].force.retrieveNow and MLValue[Term].retrieveNow.force both guarantee that all exceptions are thrown.

Note: Some operations take an Isabelle instance as an implicit argument. It is required that this instance the same as the one relative to which the MLValue was created.

A full example:

implicit val isabelle: Isabelle = new Isabelle(...)
import scala.concurrent.ExecutionContext.Implicits._

// Create an MLValue containing an integer
val intML : MLValue[Int] = MLValue(123)
// 123 is now stored in the object store

// Fetching the integer back
val int : Int = intML.retrieveNow
assert(int == 123)

// The type parameter of MLValue ensures that the following does not compile:
// val string : String = intML.retrieveNow

// We write an ML function that squares an integer and converts it into a string
val mlFunction : MLFunction[Int, String] =
  MLValue.compileFunction[Int, String]("fn i => string_of_int (i*i)")

// We can apply the function to an integer stored in the Isabelle process
val result : MLValue[String] = mlFunction(intML)
// The result is still stored in the Isabelle process, but we can retrieve it:
val resultHere : String = result.retrieveNow
assert(resultHere == "15129")

Not that the type annotations in this example are all optional, the compiler infers them automatically. We have included them for clarity only.

A

the Scala type corresponding to the ML type of the value referenced by id

Source
MLValue.scala
Linear Supertypes
Ordering
  1. Alphabetic
  2. By Inheritance
Inherited
  1. MLValue
  2. FutureValue
  3. AnyRef
  4. Any
  1. Hide All
  2. Show All
Visibility
  1. Public
  2. Protected

Instance Constructors

  1. new MLValue(id: Future[ID])

    id

    the ID of the referenced object in the Isabelle process

    Attributes
    protected

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. final def asInstanceOf[T0]: T0
    Definition Classes
    Any
  5. 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
    MLValueFutureValue
  6. def clone(): AnyRef
    Attributes
    protected[lang]
    Definition Classes
    AnyRef
    Annotations
    @throws(classOf[java.lang.CloneNotSupportedException]) @native() @HotSpotIntrinsicCandidate()
  7. def debugInfo(implicit isabelle: Isabelle, ec: ExecutionContext): String

    Returns a textual representation of the value in the ML process as it is stored in the object store (i.e., encoded as an exception).

    Returns a textual representation of the value in the ML process as it is stored in the object store (i.e., encoded as an exception). E.g., an integer 3 would be represented as "E_Int 3".

  8. final def eq(arg0: AnyRef): Boolean
    Definition Classes
    AnyRef
  9. def equals(arg0: AnyRef): Boolean
    Definition Classes
    AnyRef → Any
  10. def force: MLValue.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
  11. def forceFuture(implicit ec: ExecutionContext): Future[MLValue.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
  12. def function[D, R](implicit ev: =:=[MLValue[A], MLValue[(D) => R]]): MLFunction[D, R]

    Returns this MLValue as an MLFunction, assuming this MLValue has a type of the form MLValue[D => R].

    Returns this MLValue as an MLFunction, assuming this MLValue has a type of the form MLValue[D => R]. If this MLValue is MLValue[D => R], it means it references a function value in the ML process. Converting it to an MLFunction <: MLValue gives us access to additional methods for applying this function.

    See also

    MLFunction

  13. def function0[R](implicit ev: =:=[MLValue[A], MLValue[(Unit) => R]]): MLFunction0[R]

    Analogous to function but for functions that take a unit-valye as argument, i.e., this : MLValue[Unit => R].

    Analogous to function but for functions that take a unit-valye as argument, i.e., this : MLValue[Unit => R].

    See also

    MLFunction0

  14. def function2[D1, D2, R](implicit ev: =:=[MLValue[A], MLValue[((D1, D2)) => R]]): MLFunction2[D1, D2, R]

    Analogous to function but for functions that take a pair as argument, i.e., this : MLValue[((D1, D2)) => R].

    Analogous to function but for functions that take a pair as argument, i.e., this : MLValue[((D1, D2)) => R].

    See also

    MLFunction2

  15. def function3[D1, D2, D3, R](implicit ev: =:=[MLValue[A], MLValue[((D1, D2, D3)) => R]]): MLFunction3[D1, D2, D3, R]

    Analogous to function but for functions that take a 3-tuple as argument, i.e., this : MLValue[((D1, D2, D3)) => R].

    Analogous to function but for functions that take a 3-tuple as argument, i.e., this : MLValue[((D1, D2, D3)) => R].

    See also

    MLFunction3

  16. def function4[D1, D2, D3, D4, R](implicit ev: =:=[MLValue[A], MLValue[((D1, D2, D3, D4)) => R]]): MLFunction4[D1, D2, D3, D4, R]

    Analogous to function but for functions that take a 4-tuple as argument, i.e., this : MLValue[((D1, D2, D3, D4)) => R].

    Analogous to function but for functions that take a 4-tuple as argument, i.e., this : MLValue[((D1, D2, D3, D4)) => R].

    See also

    MLFunction4

  17. def function5[D1, D2, D3, D4, D5, R](implicit ev: =:=[MLValue[A], MLValue[((D1, D2, D3, D4, D5)) => R]]): MLFunction5[D1, D2, D3, D4, D5, R]

    Analogous to function but for functions that take a 5-tuple as argument, i.e., this : MLValue[((D1, D2, D3, D4, D5)) => R].

    Analogous to function but for functions that take a 5-tuple as argument, i.e., this : MLValue[((D1, D2, D3, D4, D5)) => R].

    See also

    MLFunction5

  18. def function6[D1, D2, D3, D4, D5, D6, R](implicit ev: =:=[MLValue[A], MLValue[((D1, D2, D3, D4, D5, D6)) => R]]): MLFunction6[D1, D2, D3, D4, D5, D6, R]

    Analogous to function but for functions that take a 6-tuple as argument, i.e., this : MLValue[((D1, D2, D3, D4, D5, D6)) => R].

    Analogous to function but for functions that take a 6-tuple as argument, i.e., this : MLValue[((D1, D2, D3, D4, D5, D6)) => R].

    See also

    MLFunction6

  19. def function7[D1, D2, D3, D4, D5, D6, D7, R](implicit ev: =:=[MLValue[A], MLValue[((D1, D2, D3, D4, D5, D6, D7)) => R]]): MLFunction7[D1, D2, D3, D4, D5, D6, D7, R]

    Analogous to function but for functions that take a 7-tuple as argument, i.e., this : MLValue[((D1, D2, D3, D4, D5, D6, D7)) => R].

    Analogous to function but for functions that take a 7-tuple as argument, i.e., this : MLValue[((D1, D2, D3, D4, D5, D6, D7)) => R].

    See also

    MLFunction7

  20. final def getClass(): Class[_ <: AnyRef]
    Definition Classes
    AnyRef → Any
    Annotations
    @native() @HotSpotIntrinsicCandidate()
  21. def hashCode(): Int
    Definition Classes
    AnyRef → Any
    Annotations
    @native() @HotSpotIntrinsicCandidate()
  22. val id: Future[ID]
  23. def insertMLValue[C[_], B](implicit ev: =:=[A, C[B]]): MLValue[C[MLValue[B]]]

    Specialized type cast that inserts MLValue[] in arbitrary positions in the type parameter of this MLValue.

    Specialized type cast that inserts MLValue[] in arbitrary positions in the type parameter of this MLValue. E.g., we can type cast this : MLValue[List[X]] to MLValue[List[MLValue[X]]] by invoking this.insertMLValue[List,X] Such type casts are safe because the the way MLValue[...] is interpreted in the type parameter to MLValue (see MLValueConverter). The same type cast could be achieved using .asInstanceOf, but insertMLValue guarantees that no unsafe cast is accidentally performed.

    Annotations
    @inline()
  24. final def isInstanceOf[T0]: Boolean
    Definition Classes
    Any
  25. def logError(message: => String)(implicit executionContext: ExecutionContext): MLValue.this.type
  26. final def ne(arg0: AnyRef): Boolean
    Definition Classes
    AnyRef
  27. final def notify(): Unit
    Definition Classes
    AnyRef
    Annotations
    @native() @HotSpotIntrinsicCandidate()
  28. final def notifyAll(): Unit
    Definition Classes
    AnyRef
    Annotations
    @native() @HotSpotIntrinsicCandidate()
  29. def removeMLValue[C[_], B](implicit ev: =:=[A, C[MLValue[B]]]): MLValue[C[B]]

    Specialized type cast that removes MLValue[] in arbitrary positions in the type parameter of this MLValue.

    Specialized type cast that removes MLValue[] in arbitrary positions in the type parameter of this MLValue. E.g., we can type cast this : MLValue[List[MLValue[X]]] to MLValue[List[X]] by invoking this.removeMLValue[List,X] Such type casts are safe because the the way MLValue[...] is interpreted in the type parameter to MLValue (see MLValueConverter). The same type cast could be achieved using .asInstanceOf, but insertMLValue guarantees that no unsafe cast is accidentally performed.

    Annotations
    @inline()
  30. def retrieve(implicit converter: Converter[A], isabelle: Isabelle, ec: ExecutionContext): Future[A]

    Retrieves the value referenced by this MLValue from the Isabelle process.

    Retrieves the value referenced by this MLValue from the Isabelle process.

    In particular, the value in the Isabelle process (a value in ML) is translated to a Scala value.

    converter

    This converter specifies how the value is to be retrieved from the Isabelle process and translated into a Scala value of type A

    isabelle

    The Isabelle instance holding the value. This must be the same Isabelle instance relative to which the MLValue was created. (Otherwise unspecified data is returned or an exception thrown.) In an application with only a single Isabelle instance that instance can safely be declared as an implicit.

    returns

    Future holding the value (as a Scala value) or an IsabelleException if the computation of that value or the transfer to Scala failed.

    Annotations
    @inline()
  31. def retrieveNow(implicit converter: Converter[A], isabelle: Isabelle, ec: ExecutionContext): A

    Like retrieve but returns the Scala value directly instread of a future (blocks till the computation and transfer finish.

    Like retrieve but returns the Scala value directly instread of a future (blocks till the computation and transfer finish.

    Annotations
    @inline()
  32. def someFuture: Future[Any]

    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
    MLValueFutureValue
  33. 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
  34. final def synchronized[T0](arg0: => T0): T0
    Definition Classes
    AnyRef
  35. def toString(): String
    Definition Classes
    AnyRef → Any
  36. final def wait(arg0: Long, arg1: Int): Unit
    Definition Classes
    AnyRef
    Annotations
    @throws(classOf[java.lang.InterruptedException])
  37. final def wait(arg0: Long): Unit
    Definition Classes
    AnyRef
    Annotations
    @throws(classOf[java.lang.InterruptedException]) @native()
  38. 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