dual calculus
Wadler's dual calculus is a term assignment system for Gentzen's system LJ; i.e., the classical sequent calculus.
1. syntax
The notation makes use of a pair of mnemonic conventions:
- unary term formers are written postfix, while unary coterm formers are written prefix;
- angle brackets enclose terms, square brackets enclose coterms, and parentheses enclose statements.
Here is some intuition for these constructs.
- forms a pair of two terms and .
- takes a continuation and essentially precomposes the first projection with it. In other words, turns from a continuation that expects a value of type into a continuation that expects a value of type . is similar.
- injects the term into a sum on the left; injects the term into a sum on the right.
- performs case analysis on a sum value, executing in case it is a left value and in case it is a right value.
- converts a coterm into a value. Specifically, a coterm that expects a value of type becomes a continuation of type .
- converts a term into a covalue. Specifically, a term becomes a covalue that, upon receiving a continuation value , passes the result of evaluating to .
- abstracts over the covariable , converting the statement into a term that yields whatever value is passed to . Likewise abstracts over the variable , converting the statement into a coterm that awaits a value for .
- Function abstraction has the usual interpretation. Function application works a little differently, though.
2. types
There are three kinds of type judgments: one for terms, one for coterms, and one for commands.
All judgments involve two lists of assumptions, one on each side of a turnstile , just as in the sequent calculus. On the left, means that the variable stands for a value of type . On the right, means that the covariable stands for a covalue of type (i.e., a computational context with a hole of type ).
For terms, means that, given the assumptions in and , the term has type . Computationally, it means that, if each variable in is assigned a value of appropriate type, then will either evaluate to a value of type or pass to a covariable in a value of appropriate type.
For coterms, means that, given the assumptions in and , the coterm has type . Computationally, it means that, if each variable in is assigned a value of appropriate type and is passed a value of type , then it will pass to some covariable in a value of appropriate type.
It may seem odd that judgments are written on the right for terms and on the left for coterms. However, they correspond respectively to right and left rules in the sequent calculus, so the choice makes sense. Also observe that the computational interpretation has a disjunctive flavor for term judgments and a conjunctive flavor for coterm judgments.
Finally, for statements, means that, given the assumptions in and , the statement is well-typed. Computationally, it means that, if each variable in is assigned a value of appropriate type, then will pass to some covariable in a value of appropriate type.
2.1. products
These correspond to the rules for conjunction in sequent calculus.
2.2. sums
These correspond to the rules for disjunction in sequent calculus.
2.3. functions
2.4. negations
Syntactically, these convert between terms and coterms. Logically, they correspond to the rules for negation.
- converts a coterm into a term: a coterm that expects a value of type becomes a term of type .
- converts a term into a coterm. Specifically, a term becomes a covalue that, upon receiving a continuation value , passes the result of evaluating to .
2.5. abstractions
Syntactically, these convert center sequents to right or left sequents. Standard sequent calculi do not distinguish classes of sequents in this way, so these rules do not correspond to any standard logical rules.
2.6. statements
Logically, this corresponds to the cut rule.
3. elimination rules
Can we recover elimination rules from the left rules?
Yes, we can. Every left rule is very much like the contrapositive of an elimination rule. An elimination rule for says something like “give me a value of type and I will extract some data from it.” A left rule for says something like “give me a place to put some data from a value of type and I will give you a place to put a value of type .” To recover an elimination rule, we simply need to feed in a value of type and tell the left rule to put the data right here. That is, if , we write , where is an expression that applies a left rule, using as the final continuation.
3.1. products
3.2. sums
3.3. functions
4. other types
4.1. cofunctions?
It's worth wondering whether we can dream up a sensible dual for functions.
Let's begin by just thinking about logic. The de Morgan dual of is , also written . (The latter notation can be justified by the equivalence .) We can derive its right rule from the left rule for implication.
And likewise, its left rule from the right rule for implication.
Using term names, the right rule becomes
and the left rule becomes
From the right rule, it is clear that a “cofunction” is fundamentally just a pair of a value and a continuation . The computational interpretation of the left rule is that, if we have a way to produce a given an , then a cofunction gives us both a and something to do with the resulting .