Let us start with an universal type
type T = (∀ a. ! a) ; Close
and write a consumer for T:
f : T -> ∀b . b -> ()
f c x = close (send x (sendType b c))
Intutively a session-∀ is associated with sendType. For universal types in general, we need
f c x = close (send x (<apply b to c>))
for which we already have syntax
f c x = close (send x (c @ b))
Kekkyoku: Universal types are universal types and so we may (must?) not distinguish the case of a session-∀ from an arbitrary-∀.
[Parenthesis. Do we need a @|> operator to sequence channel operations?
f c x = c @|> b |> send x |> close
End of parenthesis.]
Let us now consider the dual of T (now denoted by Dual T), that is, the type (∃ a. ! a) ; Wait, and write a consumer for it.
g : Dual T -> ()
g c =
let {b, c} = receiveType c in -- b is a type variable
let (x, c) = receive c in wait c -- x is of type b
I am assuming that b is unrestricted, of kind *T, so that x can be discarded.
Unlike sendType that can be understood as type application, receiveType requires four parameters. In let {a, x} = receiveType e1 in e2,
e1 is an expression of type ∃ b. T
a is a type variable standing for the type "in transit in the channel"
x : a is a term variables standing for the continuation channel and
e2 is where a and x are used (the scope of these variables)
In the functional world, existential types are used to describe packages. A type ∃ a. T describes a package T (for example, a record of queue operations) and a describes the type supporting the package (the representation, for example, a list of integer values). To open or import a package, Harper uses the syntax
open e1 as a with x in e2
Transforming open into receiveType we get
receiveType e1 as a with x in e2
which is somewhat difficult to read. Pierce instead uses the syntax
which is closer to the above proposal. (Pierce also suggests open e1 as {a, x} in e2. At this point it is worth rereading Chapter 24.)
My difficulty with this syntax is that the I and the O are misaligned. For the former we have a receiveType expression. For the latter a good old type application (in place of a sendType). Ideas?
The typing rule for the elimination of the existential type is that of Harper, adapted to the linear setting and to kinded type-variables:
Δ Γ1 |- e1 : ∃ a:k. T Δ,a:k Γ2,x:T |- e2 : T2 Δ |- T2 : k'
--------------------------------------------------------------------- ∃-Elim
Δ Γ1,Γ2 |- let {a, x} = receiveType e2 in e1 : T2
The Δ |- T2 : _ makes sure that T2 does not depend on a. This premise may be replaced by a not free in T2, because by agreement we have Δ,a:k |- T2 : k' and by strengthening we get Δ |- T2 : k'.
Reduction incorporates the idea of type-passing:
(νxy)( E1[x @ T] | E2[let {a, z} = receiveType y in e] ) -->
(νxy)( E1[x] | E2[e[T/a][y/z] )
Let us go back to the function that consumes type (∃ a. ! a) ; Wait. Function g discards the value received. Suppose instead that we'd like to return the value, as in
g' c =
let {b, c} = receiveType c in
let (x, c) = receive c in (wait c ; x)
What would be the type of g'? It can't certainly be ∀ a . (∃ a. ! a) ; Wait -> a, for this type is alpha-congruent to ∀ b . (∃ a. ! a) ; Wait -> b where it is clear that a and b are unrelated. This is the reason for the 3rd premise in rule ∃-Elim. If x cannot be returned, then it must be consumed within the function.
[To be continued]
Let us start with an universal type
and write a consumer for
T:Intutively a session-∀ is associated with
sendType. For universal types in general, we needfor which we already have syntax
Kekkyoku: Universal types are universal types and so we may (must?) not distinguish the case of a session-∀ from an arbitrary-∀.
[Parenthesis. Do we need a
@|>operator to sequence channel operations?End of parenthesis.]
Let us now consider the dual of
T(now denoted byDual T), that is, the type(∃ a. ! a) ; Wait, and write a consumer for it.I am assuming that
bis unrestricted, of kind*T, so thatxcan be discarded.Unlike
sendTypethat can be understood as type application,receiveTyperequires four parameters. Inlet {a, x} = receiveType e1 in e2,e1is an expression of type∃ b. Tais a type variable standing for the type "in transit in the channel"x : ais a term variables standing for the continuation channel ande2is whereaandxare used (the scope of these variables)In the functional world, existential types are used to describe packages. A type
∃ a. Tdescribes a packageT(for example, a record of queue operations) andadescribes the type supporting the package (the representation, for example, a list of integer values). To open or import a package, Harper uses the syntaxTransforming
openintoreceiveTypewe getwhich is somewhat difficult to read. Pierce instead uses the syntax
which is closer to the above proposal. (Pierce also suggests
open e1 as {a, x} in e2. At this point it is worth rereading Chapter 24.)My difficulty with this syntax is that the I and the O are misaligned. For the former we have a
receiveTypeexpression. For the latter a good old type application (in place of asendType). Ideas?The typing rule for the elimination of the existential type is that of Harper, adapted to the linear setting and to kinded type-variables:
The
Δ |- T2 : _makes sure thatT2does not depend ona. This premise may be replaced bya not free in T2, because by agreement we haveΔ,a:k |- T2 : k'and by strengthening we getΔ |- T2 : k'.Reduction incorporates the idea of type-passing:
Let us go back to the function that consumes type
(∃ a. ! a) ; Wait. Functiongdiscards the value received. Suppose instead that we'd like to return the value, as inWhat would be the type of
g'? It can't certainly be∀ a . (∃ a. ! a) ; Wait -> a, for this type is alpha-congruent to∀ b . (∃ a. ! a) ; Wait -> bwhere it is clear thataandbare unrelated. This is the reason for the 3rd premise in rule ∃-Elim. Ifxcannot be returned, then it must be consumed within the function.[To be continued]