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 typea
. (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 typea
. (E.g., both Long and Int correspond to the unboundedint
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 anA
in Scala - store function: how to translate an
A
in Scala into an an exception encoding an ML value of typea
and store it in the object store.
- an encoding of
MLValue(x)
automatically translatesx:A
into a value of typea
(using the retrieve function) and returns anMLValue[A]
.- If
m : MLValue[A]
, thenm.
retrieve (asynchronous) andm.
retrieveNow (synchronous) decode the ML value in the object store and return a Scala value of typeA
. - 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 theMLValue
, 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, ifMLValue[Unit].retrieveNow
orMLValue[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). IfMLValue[Term].retrieveNow
completes without exception, this is not guaranteed (because Term is a subtype of FutureValue). ButMLValue[Term].force.retrieveNow
andMLValue[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
- Alphabetic
- By Inheritance
- MLValue
- FutureValue
- AnyRef
- Any
- Hide All
- Show All
- Public
- Protected
Instance Constructors
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
- 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
- MLValue → FutureValue
- def clone(): AnyRef
- Attributes
- protected[lang]
- Definition Classes
- AnyRef
- Annotations
- @throws(classOf[java.lang.CloneNotSupportedException]) @native() @HotSpotIntrinsicCandidate()
- 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".
- final def eq(arg0: AnyRef): Boolean
- Definition Classes
- AnyRef
- def equals(arg0: AnyRef): Boolean
- Definition Classes
- AnyRef → Any
- 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
- 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.
- Definition Classes
- FutureValue
- 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 isMLValue[D => R]
, it means it references a function value in the ML process. Converting it to anMLFunction <: MLValue
gives us access to additional methods for applying this function.- See also
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- final def getClass(): Class[_ <: AnyRef]
- Definition Classes
- AnyRef → Any
- Annotations
- @native() @HotSpotIntrinsicCandidate()
- def hashCode(): Int
- Definition Classes
- AnyRef → Any
- Annotations
- @native() @HotSpotIntrinsicCandidate()
- val id: Future[ID]
- 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 castthis : MLValue[List[X]]
toMLValue[List[MLValue[X]]]
by invokingthis.insertMLValue[List,X]
Such type casts are safe because the the wayMLValue[...]
is interpreted in the type parameter toMLValue
(see MLValueConverter). The same type cast could be achieved using.asInstanceOf
, butinsertMLValue
guarantees that no unsafe cast is accidentally performed.- Annotations
- @inline()
- final def isInstanceOf[T0]: Boolean
- Definition Classes
- Any
- def logError(message: => String)(implicit executionContext: ExecutionContext): MLValue.this.type
- 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()
- 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 castthis : MLValue[List[MLValue[X]]]
toMLValue[List[X]]
by invokingthis.removeMLValue[List,X]
Such type casts are safe because the the wayMLValue[...]
is interpreted in the type parameter toMLValue
(see MLValueConverter). The same type cast could be achieved using.asInstanceOf
, butinsertMLValue
guarantees that no unsafe cast is accidentally performed.- Annotations
- @inline()
- 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 theMLValue
was created. (Otherwise unspecified data is returned or an exception thrown.) In an application with only a singleIsabelle
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()
- 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()
- 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
- MLValue → 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
- 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(classOf[java.lang.InterruptedException])
- final def wait(arg0: Long): Unit
- Definition Classes
- AnyRef
- Annotations
- @throws(classOf[java.lang.InterruptedException]) @native()
- final def wait(): Unit
- Definition Classes
- AnyRef
- Annotations
- @throws(classOf[java.lang.InterruptedException])