Multi-Level Languages are Generalized Arrows Adam Megacz - - PowerPoint PPT Presentation
Multi-Level Languages are Generalized Arrows Adam Megacz - - PowerPoint PPT Presentation
Multi-Level Languages are Generalized Arrows Adam Megacz 12-Apr-2011 1/38 Lambda Calculus Review := Int | -> | . . . e := x | e e | x . e [Var] x: x: , x: 1 e: 2 [Lam] ( x . e ) : 1 -> 2
Lambda Calculus Review
τ := Int | τ->τ | . . . e := x | e e | λx.e [Var] x:τ ⊢ x:τ Γ, x:τ1 ⊢ e:τ2 [Lam] Γ ⊢ (λx.e):τ1->τ2 Γ1 ⊢ e1:τ1 Γ2 ⊢ e2:τ1->τ2 [App] Γ1, Γ2 ⊢ e2e1:τ2 3/38
Flattening, in Detail
What follows is the simplified translation, which works only when higher-order functions are not used. Specifically, the context (area to the left of the turnstile) may not contain any variables with ->’s in their types. 5/38
Flattening, in Detail
Let’s try an example. We’re going to flatten this expression: subtract_second_from_third :: Int -> (Int -> (Int -> Int)) subtract_second_from_third x y z = z - y But first, we need to desugar it. The expression above is really just syntactic sugar for this: subtract_second_from_third = \x -> \y -> \z -> (-) z y Also, note that this expression has (-) as a free variable, with the following type: (-) :: Int -> Int -> Int We’ll come back to this. 7/38
Flattening, in Detail
Let’s try an example. We’re going to flatten this expression: subtract_second_from_third :: Int -> (Int -> (Int -> Int)) subtract_second_from_third x y z = z - y But first, we need to desugar it. The expression above is really just syntactic sugar for this: subtract_second_from_third = \x -> \y -> \z -> (-) z y Also, note that this expression has (-) as a free variable, with the following type: (-) :: Int -> Int -> Int We’ll come back to this. 7/38
Flattening, in Detail
Let’s try an example. We’re going to flatten this expression: subtract_second_from_third :: Int -> (Int -> (Int -> Int)) subtract_second_from_third x y z = z - y But first, we need to desugar it. The expression above is really just syntactic sugar for this: subtract_second_from_third = \x -> \y -> \z -> (-) z y Also, note that this expression has (-) as a free variable, with the following type: (-) :: Int -> Int -> Int We’ll come back to this. 7/38
Flattening, in Detail
The (simplified) flattening process involves six steps:
- 1. Construct the proof that the expression is well-typed
- 2. Skolemize the proof
- 3. Make contraction, and exchange explicit in the proof
- 4. Make left and right expansion explicit in the proof
- 5. Make weakening explicit in the proof
- 6. Walk the proof
In practice, steps 2-5 are performed simultaneously as one big step. In these slides they are presented as separate steps in an order which keeps each of the proofs small enough to fit on a slide. 9/38
Flattening, in Detail
The (simplified) flattening process involves six steps:
- 1. Construct the proof that the expression is well-typed
- 2. Skolemize the proof
- 3. Make contraction, and exchange explicit in the proof
- 4. Make left and right expansion explicit in the proof
- 5. Make weakening explicit in the proof
- 6. Walk the proof
In practice, steps 2-5 are performed simultaneously as one big step. In these slides they are presented as separate steps in an order which keeps each of the proofs small enough to fit on a slide. 9/38
Step 1: Construct the Proof
subtract_first_from_third = \x -> \y -> \z -> ((-) z) y
λx λy λz app app (-) z y [Var] y:Int ⊢ y:Int [Var] z:Int ⊢ z:Int ⊢ (-) : Int->Int->Int [App] z : Int ⊢ (-) z:Int->Int [App] x:Int, y:Int, z:Int ⊢ (-) z y:Int [Lam] x:Int, y:Int ⊢ \z -> (-) z y:Int->Int [Lam] x:Int ⊢ \y -> \z -> (-) z y:Int->(Int->Int) [Lam] ⊢ \x -> \y -> \z -> (-) z y:Int->(Int->(Int->Int))
11/38
Step 1: Construct the Proof
subtract_first_from_third = \x -> \y -> \z -> ((-) z) y
λx λy λz app app (-) z y [Var] y:Int ⊢ y:Int [Var] z:Int ⊢ z:Int ⊢ (-) : Int->Int->Int [App] z : Int ⊢ (-) z:Int->Int [App] x:Int, y:Int, z:Int ⊢ (-) z y:Int [Lam] x:Int, y:Int ⊢ \z -> (-) z y:Int->Int [Lam] x:Int ⊢ \y -> \z -> (-) z y:Int->(Int->Int) [Lam] ⊢ \x -> \y -> \z -> (-) z y:Int->(Int->(Int->Int))
11/38
Step 1: Construct the Proof
subtract_first_from_third = \x -> \y -> \z -> ((-) z) y
λx λy λz app app (-) z y [Var] y:Int ⊢ y:Int [Var] z:Int ⊢ z:Int ⊢ (-) : Int->Int->Int [App] z : Int ⊢ (-) z:Int->Int [App] x:Int, y:Int, z:Int ⊢ (-) z y:Int [Lam] x:Int, y:Int ⊢ \z -> (-) z y:Int->Int [Lam] x:Int ⊢ \y -> \z -> (-) z y:Int->(Int->Int) [Lam] ⊢ \x -> \y -> \z -> (-) z y:Int->(Int->(Int->Int))
11/38
Step 1: Construct the Proof
subtract_first_from_third = \x -> \y -> \z -> ((-) z) y
λx λy λz app app (-) z y [Var] y:Int ⊢ y:Int [Var] z:Int ⊢ z:Int ⊢ (-) : Int->Int->Int [App] z : Int ⊢ (-) z:Int->Int [App] x:Int, y:Int, z:Int ⊢ (-) z y:Int [Lam] x:Int, y:Int ⊢ \z -> (-) z y:Int->Int [Lam] x:Int ⊢ \y -> \z -> (-) z y:Int->(Int->Int) [Lam] ⊢ \x -> \y -> \z -> (-) z y:Int->(Int->(Int->Int))
11/38
Step 1: Construct the Proof
subtract_first_from_third = \x -> \y -> \z -> ((-) z) y
λx λy λz app app (-) z y [Var] y:Int ⊢ y:Int [Var] z:Int ⊢ z:Int ⊢ (-) : Int->Int->Int [App] z : Int ⊢ (-) z:Int->Int [App] x:Int, y:Int, z:Int ⊢ (-) z y:Int [Lam] x:Int, y:Int ⊢ \z -> (-) z y:Int->Int [Lam] x:Int ⊢ \y -> \z -> (-) z y:Int->(Int->Int) [Lam] ⊢ \x -> \y -> \z -> (-) z y:Int->(Int->(Int->Int))
11/38
Step 1: Construct the Proof
subtract_first_from_third = \x -> \y -> \z -> ((-) z) y
λx λy λz app app (-) z y [Var] y:Int ⊢ y:Int [Var] z:Int ⊢ z:Int ⊢ (-) : Int->Int->Int [App] z : Int ⊢ (-) z:Int->Int [App] x:Int, y:Int, z:Int ⊢ (-) z y:Int [Lam] x:Int, y:Int ⊢ \z -> (-) z y:Int->Int [Lam] x:Int ⊢ \y -> \z -> (-) z y:Int->(Int->Int) [Lam] ⊢ \x -> \y -> \z -> (-) z y:Int->(Int->(Int->Int))
11/38
Step 1: Construct the Proof
subtract_first_from_third = \x -> \y -> \z -> ((-) z) y
λx λy λz app app (-) z y [Var] y:Int ⊢ y:Int [Var] z:Int ⊢ z:Int ⊢ (-) : Int->Int->Int [App] z : Int ⊢ (-) z:Int->Int [App] x:Int, y:Int, z:Int ⊢ (-) z y:Int [Lam] x:Int, y:Int ⊢ \z -> (-) z y:Int->Int [Lam] x:Int ⊢ \y -> \z -> (-) z y:Int->(Int->Int) [Lam] ⊢ \x -> \y -> \z -> (-) z y:Int->(Int->(Int->Int))
11/38
Step 1: Construct the Proof
subtract_first_from_third = \x -> \y -> \z -> ((-) z) y
λx λy λz app app (-) z y [Var] y:Int ⊢ y:Int [Var] z:Int ⊢ z:Int ⊢ (-) : Int->Int->Int [App] z : Int ⊢ (-) z:Int->Int [App] x:Int, y:Int, z:Int ⊢ (-) z y:Int [Lam] x:Int, y:Int ⊢ \z -> (-) z y:Int->Int [Lam] x:Int ⊢ \y -> \z -> (-) z y:Int->(Int->Int) [Lam] ⊢ \x -> \y -> \z -> (-) z y:Int->(Int->(Int->Int))
11/38
Step 1: Construct the Proof
subtract_first_from_third = \x -> \y -> \z -> ((-) z) y
λx λy λz app app (-) z y [Var] y:Int ⊢ y:Int [Var] z:Int ⊢ z:Int ⊢ (-) : Int->Int->Int [App] z : Int ⊢ (-) z:Int->Int [App] x:Int, y:Int, z:Int ⊢ (-) z y:Int [Lam] x:Int, y:Int ⊢ \z -> (-) z y:Int->Int [Lam] x:Int ⊢ \y -> \z -> (-) z y:Int->(Int->Int) [Lam] ⊢ \x -> \y -> \z -> (-) z y:Int->(Int->(Int->Int))
11/38
Step 2: Skolemize the Proof
Now, we skolemize the proof to eliminate function types a->b. Wherever an expression of function type appears to the right of the turnstile, like this: Γ ⊢ e:α->β 12/38
Step 2: Skolemize the Proof
Now, we skolemize the proof to eliminate function types a->b. Wherever an expression of function type appears to the right of the turnstile, like this: Γ ⊢ e:α->β we will add a new skolem variable with a fresh name to the left of the turnstile and apply the expression to it, like this: a:α, Γ ⊢ e a:β 12/38
Step 2: Skolemize the Proof
Now, we skolemize the proof to eliminate function types a->b. Wherever an expression of function type appears to the right of the turnstile, like this: Γ ⊢ e:α->β we will add a new skolem variable with a fresh name to the left of the turnstile and apply the expression to it, like this: a:α, Γ ⊢ e a:β Repeated application of the procedure above will leave us with a proof which has no ->’s to the right of the turnstile. 12/38
Skolemizing Lam
y:α, Γ ⊢ e:β [Lam] Γ ⊢ (λy.e):α->β 13/38
Skolemizing Lam
y:α, Γ ⊢ e:β [Lam] Γ ⊢ (λy.e):α->β Notice what happens to the Lam rule when we skolemize it: y:α, Γ ⊢ e:β [Skolemized-Lam] a:α, Γ ⊢ (λy.e) a:β 13/38
Skolemizing Lam
y:α, Γ ⊢ e:β [Lam] Γ ⊢ (λy.e):α->β Notice what happens to the Lam rule when we skolemize it: y:α, Γ ⊢ e:β [Skolemized-Lam] a:α, Γ ⊢ (λy.e) a:β Because (λy.e) a reduces via β-reduction to e[y := a], Skolemized-Lam is nothing more than variable renaming. We can eliminate it entirely by changing the names of the variables in the proof tree above it: . . . y:α, Γ ⊢ e:β Γ ⊢ (λy.e):α->β ⇒ . . . y:α, Γ ⊢ e:β a:α, Γ ⊢ (λy.e) a:β ⇒ . . . [y:=a] a:α, Γ ⊢ e[y:=a]:β 13/38
Skolemizing App
Something interesting happens to the App rule, as well: Γ1 ⊢ e:α Γ2 ⊢ f:α->β [App] Γ1, Γ2 ⊢ f e:β Γ1 ⊢ e:α a:α, Γ2 ⊢ f a:β [App] Γ1, Γ2 ⊢ f e:β Look at what happens if we erase the variable names and expressions: Γ1 ⊢ α α, Γ2 ⊢ β [App] Γ1, Γ2 ⊢ β This is none other than the famous cut rule from logic! Main Idea: if an expression does not use higher-order functions, we can skolemize its proof to obtain one with no Lam rules or ->’s, and in which the App rules are natural-deduction cuts. 14/38
Step 2: Skolemize the Proof
Here is our proof again, showing in red the parts which will be removed by skolemization:
[Var] y:Int ⊢ y:Int [Var] z:Int ⊢ z:Int ⊢ (-) : Int->Int->Int [App] z : Int ⊢ (-) z:Int->Int [App] x:Int, y:Int, z:Int ⊢ (-) z y:Int [Lam] x:Int, y:Int ⊢ \z -> (-) z y:Int->Int [Lam] x:Int ⊢ \y -> \z -> (-) z y:Int->(Int->Int) [Lam] ⊢ \x -> \y -> \z -> (-) z y:Int->(Int->(Int->Int))
15/38
Step 2: Skolemize the Proof
Here is our proof again, showing in red the parts which will be removed by skolemization:
[Var] y:Int ⊢ y:Int [Var] z:Int ⊢ z:Int ⊢ (-) : Int->Int->Int [App] z : Int ⊢ (-) z:Int->Int [App] x:Int, y:Int, z:Int ⊢ (-) z y:Int [Lam] x:Int, y:Int ⊢ \z -> (-) z y:Int->Int [Lam] x:Int ⊢ \y -> \z -> (-) z y:Int->(Int->Int) [Lam] ⊢ \x -> \y -> \z -> (-) z y:Int->(Int->(Int->Int))
And here what is left after skolemizing it; the skolem variables are shown in red.
[Var] y:Int ⊢ y:Int [Var] z:Int ⊢ z:Int a : Int, b:Int ⊢ (-) a b : Int [App] b:Int, z : Int ⊢ (-) z b:Int [App] x:Int, y:Int, z:Int ⊢ (-) z y:Int
15/38
Step 3: Make Contraction and Exchange Explicit
You’ll notice that I played fast and loose with the order of the variables in the context; we must now use explicit rules to re-arrange the context. Here is the rule for exchange:
A, B ⊢ C [Exch] B, A ⊢ C
And here is our proof with exchange made explicit:
[Var] y:Int ⊢ y:Int [Var] z:Int ⊢ z:Int a : Int, b:Int ⊢ (-) a b : Int [App] z:Int, b : Int ⊢ (-) z b:Int [Exch] b : Int, z:Int ⊢ (-) z b : Int [App] x:Int, y:Int, z:Int ⊢ (-) z y:Int
16/38
Step 4: Make Left and Right Expansion Explicit
Our [App] rule looks like this: A ⊢ B X, B ⊢ C [App] X, A ⊢ C Notice that in the hypotheses, the “inner pair” don’t match. We would prefer to use [App’], which requires that they do match: A ⊢ B B ⊢ C [App’] A ⊢ C A ⊢ B [Left] X, A ⊢ X, B A ⊢ B [Right] X, A ⊢ B, X We can rewrite any use of [App] using [App’] and [Left] or [Right]: A ⊢ B [Left] X, A ⊢ X, B X, B ⊢ C [App’] X, A ⊢ C 17/38
Step 4: Make Left and Right Expansion Explicit
Here is what our proof looks like with [App’] instead of [App] and explicit [Left] and [Right]:
[Var] y:Int ⊢ y:Int [Right] y:Int, z:Int ⊢ y:Int, z:Int [Var] z:Int ⊢ z:Int [Right] z:Int, b:Int ⊢ z:Int, b:Int a : Int, b:Int ⊢ (-) a b : Int [App’] z:Int, b : Int ⊢ (-) z b:Int [Exch] b : Int, z:Int ⊢ (-) z b : Int . . . b : Int, z:Int ⊢ (-) z b : Int [App’] x:Int, y:Int, z : Int ⊢ (-) z y:Int
18/38
Step 5: Make Weakening Structurally Explicit
Finally, you’ll notice that although we never used the variable y, I never explicitly threw it away. We will now do that using the [Weak] rule:
[Weak] q:α ⊢
Here is the result:
[Weak] x:Int ⊢ [Right] x:Int, y:Int, z:Int ⊢ , y:Int, z:Int [Var] y:Int ⊢ y:Int [Left] z:Int, y:Int ⊢ z:Int, y:Int [Var] z:Int ⊢ z:Int [Left] b:Int, z:Int ⊢ b:Int, z:Int a : Int, b:Int ⊢ (-) a b : Int [App’] z:Int, b : Int ⊢ (-) z b:Int [Exch] b : Int, z:Int ⊢ (-) z b : Int . . . b : Int, z:Int ⊢ (-) z b : Int [App’] y:Int, z : Int ⊢ (-) z y:Int . . . y:Int, z : Int ⊢ (-) z y:Int [LeftUnit] , y:Int, z:Int ⊢ (-) z y:Int [App’] x:Int, y:Int, z:Int ⊢ (-) z y:Int
19/38
Step 6: Walk the Proof
Almost there! We now “walk” the proof from the bottom to the top, doing a purely local translation. Here is the rule for the translation function − on proofs, whose argument is a proof and whose result is a Haskell expression.
- .
. . H1 · · · . . . Hn [R] C
- = R
- .
. . H1
- · · ·
- .
. . Hn
- Var
= id App’ = >>> Lam = skolemized away App = skolemized away Weak = ga drop >>> Cont = ga copy >>> Exch = ga swap >>> Right = ga first Left = ga second LeftUnit = ga cancell >>> RightUnit = ga cancelr >>> LeftCancel = ga uncancell >>> RightCancel = ga uncancelr >>> Assoc = ga assoc >>> UnAssoc = ga unassoc >>> 20/38
Step 6: Walk the Proof
- [Weak]
x:Int ⊢ [Right] x:Int, y:Int, z:Int ⊢ , y:Int, z:Int [Var] y:Int ⊢ y:Int [Right] y:Int, z:Int ⊢ y:Int, z:Int [Var] z:Int ⊢ z:Int [Right] z:Int, b:Int ⊢ z:Int, b:Int a : Int, b:Int ⊢ (-) a b : Int [App’] z:Int, b : Int ⊢ (-) z b:Int [Exch] b : Int, z:Int ⊢ (-) z b : Int . . . b : Int, z:Int ⊢ (-) z b : Int [App’] y:Int, z : Int ⊢ (-) z y:Int . . . y:Int, z : Int ⊢ (-) z y:Int [LeftUnit] , y:Int, z:Int ⊢ (-) z y:Int [App’] x:Int, y:Int, z:Int ⊢ (-) z y:Int
- 21/38
Step 6: Walk the Proof
- [Weak]
x:Int ⊢ [Right] x:Int, y:Int, z:Int ⊢ , y:Int, z:Int
- >>>
- [Var]
y:Int ⊢ y:Int [Right] y:Int, z:Int ⊢ y:Int, z:Int [Var] z:Int ⊢ z:Int [Right] z:Int, b:Int ⊢ z:Int, b:Int a : Int, b:Int ⊢ (-) a b : Int [App’] z:Int, b : Int ⊢ (-) z b:Int [Exch] b : Int, z:Int ⊢ (-) z b : Int . . . b : Int, z:Int ⊢ (-) z b : Int [App’] y:Int, z : Int ⊢ (-) z y:Int . . . y:Int, z : Int ⊢ (-) z y:Int [LeftUnit] , y:Int, z:Int ⊢ (-) z y:Int
- 22/38
Step 6: Walk the Proof
(ga first
[Weak] x:Int ⊢ ) >>>
- [Var]
y:Int ⊢ y:Int [Right] y:Int, z:Int ⊢ y:Int, z:Int [Var] z:Int ⊢ z:Int [Right] z:Int, b:Int ⊢ z:Int, b:Int a : Int, b:Int ⊢ (-) a b : Int [App’] z:Int, b : Int ⊢ (-) z b:Int [Exch] b : Int, z:Int ⊢ (-) z b : Int . . . b : Int, z:Int ⊢ (-) z b : Int [App’] y:Int, z : Int ⊢ (-) z y:Int . . . y:Int, z : Int ⊢ (-) z y:Int [LeftUnit] , y:Int, z:Int ⊢ (-) z y:Int
- 23/38
Step 6: Walk the Proof
(ga first ga drop) >>>
- [Var]
y:Int ⊢ y:Int [Right] y:Int, z:Int ⊢ y:Int, z:Int [Var] z:Int ⊢ z:Int [Right] z:Int, b:Int ⊢ z:Int, b:Int a : Int, b:Int ⊢ (-) a b : Int [App’] z:Int, b : Int ⊢ (-) z b:Int [Exch] b : Int, z:Int ⊢ (-) z b : Int . . . b : Int, z:Int ⊢ (-) z b : Int [App’] y:Int, z : Int ⊢ (-) z y:Int . . . y:Int, z : Int ⊢ (-) z y:Int [LeftUnit] , y:Int, z:Int ⊢ (-) z y:Int
- 24/38
Step 6: Walk the Proof
(ga first ga drop) >>> (ga cancell >>>
- [Var]
y:Int ⊢ y:Int [Right] y:Int, z:Int ⊢ y:Int, z:Int [Var] z:Int ⊢ z:Int [Right] z:Int, b:Int ⊢ z:Int, b:Int a : Int, b:Int ⊢ (-) a b : Int [App’] z:Int, b : Int ⊢ (-) z b:Int [Exch] b : Int, z:Int ⊢ (-) z b : Int . . . b : Int, z:Int ⊢ (-) z b : Int [App’] y:Int, z : Int ⊢ (-) z y:Int
- )
25/38
Step 6: Walk the Proof
(ga first ga drop) >>> (ga cancell >>>
(
- [Var]
y:Int ⊢ y:Int [Right] y:Int, z:Int ⊢ y:Int, z:Int
- >>>
- [Var]
z:Int ⊢ z:Int [Right] z:Int, b:Int ⊢ z:Int, b:Int a : Int, b:Int ⊢ (-) a b : Int [App’] z:Int, b : Int ⊢ (-) z b:Int [Exch] b : Int, z:Int ⊢ (-) z b : Int
- ))
26/38
Step 6: Walk the Proof
(ga first ga drop) >>> (ga cancell >>>
((ga first
[Var] y:Int ⊢ y:Int ) >>>
- [Var]
z:Int ⊢ z:Int [Right] z:Int, b:Int ⊢ z:Int, b:Int a : Int, b:Int ⊢ (-) a b : Int [App’] z:Int, b : Int ⊢ (-) z b:Int [Exch] b : Int, z:Int ⊢ (-) z b : Int
- ))
27/38
Step 6: Walk the Proof
(ga first ga drop) >>> (ga cancell >>> ((ga first id) >>>
- [Var]
z:Int ⊢ z:Int [Right] z:Int, b:Int ⊢ z:Int, b:Int a : Int, b:Int ⊢ (-) a b : Int [App’] z:Int, b : Int ⊢ (-) z b:Int [Exch] b : Int, z:Int ⊢ (-) z b : Int
- ))
28/38
Step 6: Walk the Proof
(ga first ga drop) >>> (ga cancell >>> ((ga first id) >>> (ga swap >>>
- [Var]
z:Int ⊢ z:Int [Right] z:Int, b:Int ⊢ z:Int, b:Int a : Int, b:Int ⊢ (-) a b : Int [App’] z:Int, b : Int ⊢ (-) z b:Int
- )))
29/38
Step 6: Walk the Proof
(ga first ga drop) >>> (ga cancell >>> ((ga first id) >>> (ga swap >>>
- [Var]
z:Int ⊢ z:Int [Right] z:Int, b:Int ⊢ z:Int, b:Int
- >>> (
a : Int, b:Int ⊢ (-) a b : Int ))))
30/38
Step 6: Walk the Proof
(ga first ga drop) >>> (ga cancell >>> ((ga first id) >>> (ga swap >>> (ga first
[Var] z:Int ⊢ z:Int ) >>> ( a : Int, b:Int ⊢ (-) a b : Int ))))
31/38
Step 6: Walk the Proof
(ga first ga drop) >>> (ga cancell >>> ((ga first id) >>> (ga swap >>> (ga first id) >>> (
a : Int, b:Int ⊢ (-) a b : Int ))))
32/38
Step 6: Walk the Proof
(ga first ga drop) >>> (ga cancell >>> ((ga first id) >>> (ga swap >>> (ga first id) >>> (
a : Int, b:Int ⊢ (-) a b : Int ))))
Hrm, what do we do about that annoying left-over hypothesis we mentioned earlier? 33/38
Step 6: Walk the Proof
(ga first ga drop) >>> (ga cancell >>> ((ga first id) >>> (ga swap >>> (ga first id) >>> (
a : Int, b:Int ⊢ (-) a b : Int ))))
Hrm, what do we do about that annoying left-over hypothesis we mentioned earlier? We turn it into a variable of garrow type! 33/38
Step 6: Walk the Proof
(ga first ga drop) >>> (ga cancell >>> ((ga first id) >>> (ga swap >>> (ga first id) >>> (
a : Int, b:Int ⊢ (-) a b : Int ))))
flattened :: GArrow g (**) u => g (Int**Int) Int
- - a variable for the flattened "minus"
- > g (Int**(Int**Int)) Int
- - the resulting term
flattened minus = ga_first ga_drop >>> ga_cancell >>> ga_first id >>> ga_swap >>> ga_first id >>> minus
35/38
Boxes and Wires
flattened :: GArrow g (**) u => g (Int**Int) Int
- - a variable for the flattened "minus"
- > g (Int**(Int**Int)) Int
- - the resulting term
flattened minus = ga_first ga_drop >>> ga_cancell >>> ga_first id >>> ga_swap >>> ga_first id >>> minus
x z drop y first cancell z () y id first swap z y z y y z id first x y minus