scheme.tl- invokeWithLayer#da9b0d0d {X:Type} layer:int query:!X = X;
复制代码 ! modifierIn TL, the idempotent operator ! can modify any type, actually making surface values be allowed when its constant values are serialized. However, if T is a standard function like S1->..->Sr->Type, then !T is defined using the equation (!T) a1 ... ar = !(T a1 ... ar), for any a1:S1, ..., ar:Sr. The ! operator is only allowed in a definition of the types of fields of functional combinators. It is usually used as a type prefix, for example: set_timeout {X:Type} timeout:int f:!X = X;In this case, the set_timeout “wrapper” is defined. It takes two explicit parameters: the integer timeout and a surface expression of type X. X : Type is itself an implicit parameter (it is not explicitly stated, rather it is inferred from the values of the other parameters and their types). A similar kind of wrapper may be helpful for modifying the action of RPC queries (which are surface expressions of various types). For example, suppose we have the function factorial n:int = int;then we can wrap the RPC query (factorial 100) as follows: (set_timeout 200 (factorial 100)). This expression is still a surface value of type int, which means it can be passed as an RPC query. A consecutive pair of two computations is another example: pair {X Y : Type} x:X y:Y = Pair X Y; // constructorseq_pair {X Y : Type} x:!X y:!Y = Pair X Y; // functional wrapper for sequential computationpar_pair {X Y : Type} x:!X y:!Y = Pair X Y; // functional wrapper for parallel computationNow the RPC query (seq_pair (factorial 2) (factorial 3)) : Pair int int first calculates factorial 2, then factorial 3, and returns the pair (pair 2 6). In this case, the sequence of operations isn’t important, because they do not have side effects. It would have been just as well to use (par_pair (factorial 2) (factorial 3)). However, this is not always the case. We can also define an analogy to a “comma” operation: comma {X Y : Type} x:!X y:!Y = Y;For example, this operation could first calculate x, then forget the result, calculate y, and return y. Note that the semantics of the seq_pair, par_pair and comma wrappers are indeed defined where they are implemented (like the semantics of all other functional combinators), not by their TL declaration. In principle, polymorphic wrappers like set_timeout can also be applied, for example, to “annotate” a RPC response’s constant values. For example, the server might return a response to a query together with the time it was calculated. However, a value of type !X must be constant, because that is what is expected as the enclosing expression’s value. In other words, set_timeout 239 E is a constant/surface value of type X if and only if E is such itself.
|