Packages

object MLValue extends OperationCollection

Ordering
  1. Alphabetic
  2. By Inheritance
Inherited
  1. MLValue
  2. OperationCollection
  3. AnyRef
  4. Any
  1. Hide All
  2. Show All
Visibility
  1. Public
  2. Protected

Type Members

  1. abstract class Converter[A] extends AnyRef

    An instance of this class describes the relationship between a Scala type A, the corresponding ML type a, and the representation of values of type a as exceptions in the object store.

    An instance of this class describes the relationship between a Scala type A, the corresponding ML type a, and the representation of values of type a as exceptions in the object store. To support new types, a corresponding Converter object/class needs to be declared.

    We explain how a converter works using the example of IntConverter.

    The first step is to decide which Scala type and which ML type should be related. In this case, we choose scala.Int on the Scala side, and int on the ML side. We declare the correspondence using the mlType method:

    final object IntConverter extends MLValue.Converter[A] {
      override def mlType = "int"
      ...
    }

    Next, we have to decide how decide how code is converted from an int to an exception (so that it can be stored in the object store). In this simple case, we first declare a new exception for holding integers:

    isabelle.executeMLCodeNow("exception E_Int of int")

    This should be done globally (once per Isabelle instance). Declaring two (even identical) exceptions with the same name E_Int must be avoided! See OperationCollection for utilities how to manage this. (E_Int specifically does not need to be declared since it is predeclared.)

    We define the method valueToExn that returns the ML source code to convert an ML value of type int to an exception:

    final object IntConverter extends MLValue.Converter[A] {
        ...
        override def valueToExn(implicit isabelle: Isabelle, ec: ExecutionContext): String = "fn x => E_Int x"  // or equivalently: = "E_Int"
        ...
      }

    We also need to convert in the opposite direction:

    final object IntConverter extends MLValue.Converter[A] {
      ...
      override def exnToValue(implicit isabelle: Isabelle, ec: ExecutionContext): String = "fn (E_Int x) => x"
      ...
    }

    (Best add some meaningful exception in case of match failure, e.g., using boilerplate from MLValue.matchFailExn. Omitted for clarity in this example.)

    Next, we need to write a function for retrieving integer values from the object store (method retrieve). It gets a value : MLValue[Int] as input and has to return a Future[Int] containing the stored integer. In principle, there are not restrictions how this is done but the simplest way is the following approach:

    • Decide on an encoding of the integer i as a tree in the Data data structure. (In this case, simply DInt(i) will do the trick.)
    • Define an MLRetrieveFunction retrieveInt that performs this encoding on the ML side, i.e., we need to write ML code for a function of type int -> data. (data is the ML analogue of Data, see the documentation of Data.)
    • Retrieve the value by invoking retrieveInt (gives a Future[Data])
    • Convert the resulting Data to an Int. That is:
    final object IntConverter extends MLValue.Converter[A] {
      ...
      override def retrieve(value: MLValue[Int])
                           (implicit isabelle: Isabelle, ec: ExecutionContext): Future[Int] = {
         val retrieveInt = MLRetrieveFunction[Int]("fn i => DInt i")   // compile retrieveInt
         for (data <- retrieveInt(value.id); // invoke retrieveInt to transfer from Isabelle
              DInt(long) = data)             // decode the data (simple pattern match)
           yield long.toInt   // return the integer
      }
      ...
    }

    Note that val retrieveInt = ... was written inside the function retrieve for simplicity here. However, since it invokes the ML compiler, it should be invoked only once (per Isabelle instance, like the executeMLCodeNow above). See OperationCollection for an auxiliary class helping to manage this.

    Finally, we also need a function store that transfers an integer into the Isabelle object store. Again, the easiest way is to use the following steps:

    • Define an encoding of integers as Data trees (we use the same encoding as before)
    • Define an MLStoreFunction storeInt that decodes the data back to an int on the ML side, i.e., we need to write ML code for a function of type data -> int.
    • Encode the integer to be stored as Data
    • Invoke storeInt to transfer the Data to ML and store the integer in the object store. That is:
    final object IntConverter extends MLValue.Converter[A] {
      ...
      override def store(value: Int)(implicit isabelle: Isabelle, ec: ExecutionContext): MLValue[Int] = {
        val storeInt = MLStoreFunction[Int]("fn DInt i => i")   // compile storeInt
        val data = DInt(value)       // encode the integer as Data
        Ops.storeInt(data)           // invoke storeInt to get the MLValue
      }
    }

    Note that val retrieveInt = ... was written inside the function retrieve for simplicity here. Like above for storeInt, this should be done only once (per Isabelle instance).

    This concludes the definition of the Converter. Finally, the converter should be made available as an implicit value. That is, we define in a suitable place

    implicit val intConverter = IntConverter

    so that intConverter can be imported as an implicit where needed. (And if the converter we constructed is not an object but a class taking other converters as arguments, we instead write something like

    implicit def listConverter[A](implicit converter: Converter[A]): ListConverter[A] = new ListConverter()(converter)

    or similar.)

    Notes

    • Several Scala types can correspond to the same ML type (e.g., Int and Long both correspond to int).
    • If the converters for two Scala types A,B additionally have the same encoding as exceptions (defined via valueToExn, exnToValue in their Converters), then MLValue[A] and MLValue[B] can be safely typecast into each other.
    • It is not recommended to have the same Scala type A for two different ML types a1 and a2 (or for the same ML type but with different encoding). First, this would mean that there have to be two different instances of Converter[A] available (which means Scala cannot automatically choose the right one). Second, it means that one has to be manually keep track which Converter was used for which value (no type safety).
    • The attentive reader will notice that we use MLRetrieveFunction.apply and MLStoreFunction.apply when defining the converter, but that these functions take the converter we are currently defining as an implicit argument! However, this cyclic dependency is not a problem because MLRetrieveFunction.apply and MLStoreFunction.apply never invoke store and retrieve from the converter, so we can call those apply functions from store and retrieve.
    • In simple cases (when A is simply supposed to be a wrapper around a reference to a value in the Isabelle process, constructions of converters are simplified by using MLValueWrapper or AdHocConverter.
    A

    the Scala type for which a corresponding ML type is declared

  2. class Ops extends AnyRef
    Attributes
    protected[mlvalue]

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 Ops(implicit isabelle: Isabelle, ec: ExecutionContext): Ops

    Returns an instance of type Ops.

    Returns an instance of type Ops. It is guaranteed that for each instance isabelle, exactly one instance of Obs is created (using the ec from the first such invocation). (If you see this doc string in a class different from OperationCollection but no definition of the class Ops, treat this function as if it was private.)

    Definition Classes
    OperationCollection
  5. def apply[A](value: A)(implicit conv: Converter[A], isabelle: Isabelle, executionContext: ExecutionContext): MLValue[A]

    Creates an MLValue containing the value value.

    Creates an MLValue containing the value value. This transfers value to the Isabelle process and stores it in the object store there.

    returns

    an MLValue that references the location in the object store

    Annotations
    @inline()
  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 compileFunction[D1, D2, D3, D4, D5, D6, D7, R](ml: String)(implicit isabelle: Isabelle, ec: ExecutionContext, converter1: Converter[D1], converter2: Converter[D2], converter3: Converter[D3], converter4: Converter[D4], converter5: Converter[D5], converter6: Converter[D6], converter7: Converter[D7], converterR: Converter[R]): MLFunction7[D1, D2, D3, D4, D5, D6, D7, R]

    Analogous to compileFunction[D1,D2,R], except for 7-tuples instead of 2-tuples.

  9. def compileFunction[D1, D2, D3, D4, D5, D6, R](ml: String)(implicit isabelle: Isabelle, ec: ExecutionContext, converter1: Converter[D1], converter2: Converter[D2], converter3: Converter[D3], converter4: Converter[D4], converter5: Converter[D5], converter6: Converter[D6], converterR: Converter[R]): MLFunction6[D1, D2, D3, D4, D5, D6, R]

    Analogous to compileFunction[D1,D2,R], except for 6-tuples instead of 2-tuples.

  10. def compileFunction[D1, D2, D3, D4, D5, R](ml: String)(implicit isabelle: Isabelle, ec: ExecutionContext, converter1: Converter[D1], converter2: Converter[D2], converter3: Converter[D3], converter4: Converter[D4], converter5: Converter[D5], converterR: Converter[R]): MLFunction5[D1, D2, D3, D4, D5, R]

    Analogous to compileFunction[D1,D2,R], except for 5-tuples instead of 2-tuples.

  11. def compileFunction[D1, D2, D3, D4, R](ml: String)(implicit isabelle: Isabelle, ec: ExecutionContext, converter1: Converter[D1], converter2: Converter[D2], converter3: Converter[D3], converter4: Converter[D4], converterR: Converter[R]): MLFunction4[D1, D2, D3, D4, R]

    Analogous to compileFunction[D1,D2,R], except for 4-tuples instead of 2-tuples.

  12. def compileFunction[D1, D2, D3, R](ml: String)(implicit isabelle: Isabelle, ec: ExecutionContext, converter1: Converter[D1], converter2: Converter[D2], converter3: Converter[D3], converterR: Converter[R]): MLFunction3[D1, D2, D3, R]

    Analogous to compileFunction[D1,D2,R], except for 3-tuples instead of 2-tuples.

  13. def compileFunction[D1, D2, R](ml: String)(implicit isabelle: Isabelle, ec: ExecutionContext, converter1: Converter[D1], converter2: Converter[D2], converterR: Converter[R]): MLFunction2[D1, D2, R]

    Like compileFunction[D,R], except that the ML code ml must be a function of type d1 * d2 -> r where d1,d2,r are the ML types corresponding to D1,D2,R.

    Like compileFunction[D,R], except that the ML code ml must be a function of type d1 * d2 -> r where d1,d2,r are the ML types corresponding to D1,D2,R. The resulting MLFunction2 f can then be invoked also as f(x1,x2) and not only as f((x1,x2)) (as would be the case if we had used compileFunction[D,R][(D1,D2),R](ml) to compile the function).

  14. def compileFunction[D, R](ml: String)(implicit isabelle: Isabelle, ec: ExecutionContext, converterD: Converter[D], converterR: Converter[R]): MLFunction[D, R]

    Compiles an ML function and inserts it into the object store.

    Compiles an ML function and inserts it into the object store.

    ml must compile to an ML value of type d -> r where d,r are the ML type corresponding to D,R (as specified by the implicit Converters). Then the result is converted to an exception and stored in the object store. An MLFunction referencing that object is returned. (An MLFunction is an MLValue with some extra methods for evaluating functions.)

    For functions with more than one argument, see also compileFunction[D1,D2,R], compileFunction[D1,D2,D3,R], etc.

  15. def compileFunction0[R](ml: String)(implicit isabelle: Isabelle, ec: ExecutionContext, converter: Converter[R]): MLFunction0[R]

    Like compileFunction[D,R], except that the ML code ml must be a function of type unit -> r where r is the ML type corresponding to R.

    Like compileFunction[D,R], except that the ML code ml must be a function of type unit -> r where r is the ML type corresponding to R. The resulting MLFunction2 f can then be invoked also as f() and not only as f(()) (as would be the case if we had used compileFunction[D,R][Unit,R](ml) to compile the function).

  16. def compileValue[A](ml: String)(implicit isabelle: Isabelle, ec: ExecutionContext, converter: Converter[A]): MLValue[A]

    Compiles ML code ml and inserts it into the object store.

    Compiles ML code ml and inserts it into the object store.

    ml must compile to an ML value of type a where a is the ML type corresponding to A (as specified by the implicit Converter). Then the result is converted to an exception and stored in the object store. An MLValue referencing that object is returned.

    If ml is an ML function, compileFunction below might be more convenient.

  17. def compileValueRaw[A](ml: String)(implicit isabelle: Isabelle, ec: ExecutionContext): MLValue[A]

    Compiles ml code and inserts it into the object store (without any conversion).

    Compiles ml code and inserts it into the object store (without any conversion).

    ml must compile to an ML value of type exn that is the encoding of some Scala value of type A. (As specified by the Converter for A, even though that converter is not actually used by this function.)

    The function does not check whether the encoding is correct for the type A! (And if that is not the case, the returned MLValue breaks type-safety.)

    In most situations, it is preferrable to use higher level compilation functions such as compileValue or compileFunction or MLStoreFunction or MLRetrieveFunction that take care of the encoding as exceptions automatically.

  18. final def eq(arg0: AnyRef): Boolean
    Definition Classes
    AnyRef
  19. def equals(arg0: AnyRef): Boolean
    Definition Classes
    AnyRef → Any
  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. def init()(implicit isabelle: Isabelle, executionContext: ExecutionContext): Unit

    Makes sure an Ops instance for the instance isabelle is initialized.

    Makes sure an Ops instance for the instance isabelle is initialized. This is useful when code needs to be sure that the global initialization inside the Ops class has happened (e.g., declarations of ML types via Isabelle.executeMLCodeNow) even if it does not access any of the fields in the Ops class.

    Can safely be called several times with the same isabelle and/or executionContext.

    Definition Classes
    OperationCollection
  23. final def isInstanceOf[T0]: Boolean
    Definition Classes
    Any
  24. def matchFailData(name: String): String

    Utlity method for generating ML code.

    Utlity method for generating ML code. Analogous to matchFailExn, but for cases when we pattern match a value of type data.

    Annotations
    @inline()
  25. def matchFailExn(name: String): String

    Utility method for generating ML code.

    Utility method for generating ML code. It returns an ML fragment that can be used as the fallback case when pattern matching exceptions, the fragment raises an error with a description of the exception.

    Example: Instead of ML code "fn E_Int i => i", we can write s"fn E_Int i => i | ${matchFailExn("my function")}" to get more informative error messages on pattern match failures.

    name

    A short description of the purpose of the match/ML function that is being written. Will be included in the error message.

    Annotations
    @inline()
  26. final def ne(arg0: AnyRef): Boolean
    Definition Classes
    AnyRef
  27. def newOps(implicit isabelle: Isabelle, ec: ExecutionContext): Ops

    Should construct an instance of type Ops

    Should construct an instance of type Ops

    Attributes
    protected
    Definition Classes
    MLValueOperationCollection
  28. final def notify(): Unit
    Definition Classes
    AnyRef
    Annotations
    @native() @HotSpotIntrinsicCandidate()
  29. final def notifyAll(): Unit
    Definition Classes
    AnyRef
    Annotations
    @native() @HotSpotIntrinsicCandidate()
  30. def removeFuture[A](future: Future[MLValue[A]])(implicit ec: ExecutionContext): MLValue[A]

    Converts a future containing an MLValue into an MLValue.

    Converts a future containing an MLValue into an MLValue.

    The resulting MLValue then holds both the computation of the future, as well as the computation held by the MLValue contained in that future.

  31. final def synchronized[T0](arg0: => T0): T0
    Definition Classes
    AnyRef
  32. def toString(): String
    Definition Classes
    AnyRef → Any
  33. def unsafeFromId[A](id: ID): MLValue[A]

    Same as unsafeFromId(Future[ID]), except that id is given directly and not as a Future.

  34. def unsafeFromId[A](id: Future[ID]): MLValue[A]

    Unsafe operation for creating an MLValue.

    Unsafe operation for creating an MLValue. It is the callers responsibility to ensure that id refers to an ML value of the right type in the object store. Using this function should rarely be necessary, except possibly when defining new Converters.

  35. final def wait(arg0: Long, arg1: Int): Unit
    Definition Classes
    AnyRef
    Annotations
    @throws(classOf[java.lang.InterruptedException])
  36. final def wait(arg0: Long): Unit
    Definition Classes
    AnyRef
    Annotations
    @throws(classOf[java.lang.InterruptedException]) @native()
  37. 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 OperationCollection

Inherited from AnyRef

Inherited from Any

Ungrouped