2. Overview of this talk
• (1) Introduction
• CbPV
• Embedding CbV and CbN strategy in the same system
• (2) Semantics
• CbV, CbN’s semantics using monads
• CbPV’s semantics, using EM adjunction
7. Introduction
• How can we handle them in a single calculus?
• Need to control evaluation order
• Call-by-push-value calculus
• distinction between “values” and “computations”
• Values: what do not need evaluation
• Computations: what need evaluation
9. Introduction
• [Levy, 2016] (p. 32)
• return and to
• like Haskell’s return
and >>=
• thunk and force
• No counterparts in
Haskell
10. Introduction
• [Levy, 2016] (p. 37)
• Embedding of CbV to
CbPV
• In function
application, N is
evaluated first
11. Introduction
• [Levy, 2016] (p. 38)
• Embedding of CbN to
CbPV
• In function
application,
evaluation of N is
delayed (until the
thunk is evaluated)
12. Summary
• We have a calculus call-by-push-value
• We have embeddings of CbV and CbN to CbPV
13. Semantics
• (Denotational) semantics of pure typed lambda calculus is CCC (like
Sets)
• Types -> objects, terms -> arrows
• [𝐴] ∈ 𝑂𝑏(𝐶)
• 𝐴 → 𝐵 = 𝐵 𝐴
, 𝐴 × 𝐵 = 𝐴 × 𝐵 , 𝐴 + 𝐵 = 𝐴 + [𝐵]
• Semantics of 𝑥1: 𝐴1, … , 𝑥 𝑛: 𝐴 𝑛 ⊢ 𝑀: 𝐵 is 𝑀 : A1 × ⋯ 𝐴 𝑛 → [𝐵]
• What about non-pure computations?
• Use monads to define denotational semantics
• CbV and CbN need different categories
• CbV -> Kl(T), CbN -> EM(T)
14. Semantics
• CbV’s semantics: Kl(T)
• Due to Moggi (1988)
• Figure from [Levy, 2016] (p.
15)
• Types -> objects in Kl(T) =
objects in C
• Terms -> arrows in Kl(T) =
Kleisli arrows
15. Semantics
• CbN’s semantics: EM(T)
• Eilenberg-Moore category
• Figure from [Levy, 2016] (p.
29)
• Types -> objects in EM(T) =
EM algebras
• Terms -> An arrow Γ → 𝑌
(in C) for some EM algebra 𝑌
16. Semantics
• CbPV’s semantics: The adjunction 𝐹: 𝐶 ↔ 𝐸𝑀(𝑇): 𝑈
• Value -> object in C
• Computation -> object in EM(T) (Eilenberg-Moore algebra)
• Embedding of CbV and CbN preserves semantics:
• Recall 𝐴 → 𝐵 in CbV becomes 𝑈(𝐴 → 𝐹𝐵) in CbPV
• This is isomorphic to 𝐴 → 𝑇𝐵!
• (𝐴 → − ) is a limit, so it is preserved by 𝑈 (right adjoint of 𝐹)
17. Semantics
• 𝐹 and 𝑈 are adjoint functors
• Recall: ([Levy, 2016] (p. 30))
18. Summary
• Embedding of CbV and CbN preserves semantics
• Monad is decomposed into adjunction
19. References
• [Levy, 2016] P.B.Levy, A tutorial on call-by-push-value (2016)
https://www.cs.bham.ac.uk/~pbl/papers/cbpvefftt.pdf
• It describes denotational semantics of CbV and CbN first, then introduces
CbPV using them.
• [Levy, 1999] P.B.Levy. Call-By-Push-Value: A Subsuming Paradigm
(Extended Abstract) (1999)
• [Moggi, 1988] E. Moggi, Computational lambda-calculus and monads
(1988)
Hinweis der Redaktion
Hello, everyone. I would like to talk about call-by-push-value cal.
Here is the overview of this talk.
First we briefly review the lambda calculus, and two well-known evaluation strategies, call-by-value and call-by-name. Then we introduce the calculus named call-by-push-value and how ordinary lambda calculi are embedded in it.
(TODO if we have time) Second we define the denotational semantics of call-by-push-value calculus on adjunction. This semantics subsumes ordinary semantics of call-by-value and call-by-name lambda calculi using monads.
There is a supplementary material for this talk. It is the slide “The tutorial on call-by-push-value” written by Paul Blain Levy. I provided the link to this, so if you have any questions, it will be helpful.
(54 sec)
Here we consider an ordinary typed lambda calculus, with error handling and printing. Here are the rules of this system. Types are generated by Boolean, sum and arrow. Terms are defined as usual, except that they have case analyses (for Boolean and sum types) and let expressions.
Here are constructs that have side effects. We have two kinds of side effects: error handling and printing. In this setting, behavior of these constructs depends on the evaluation strategy, in other words, in which order we calculate terms.
This is an evaluation strategy named “call-by-value”. This name comes from the feature that when we evaluate function applications, arguments are fully evaluated before parameters are replaced with arguments. Let expressions are dealt with like function applications.
There is another evaluation strategy named “call-by-name”. In contrast to call-by-value strategy, call-by-name strategy substitutes parameters with arguments before it evaluates arguments.
We want to handle these two evaluation strategies in a single calculus. In order to achieve that, we need to somehow extend the calculus. That’s because we need to take care of what to evaluate and the order of evaluation.
The system is TODO call-by-push-value calculus. It achieves this goal to make a distinction between values and computations.
What does it mean?
This is the type system of call-by-push-values. Computation types are underlined.
We have return and to syntax. Return gives a computation that simply returns the given value. to expression evaluates M, and get a value and replace x with it in N, and then evaluate N.
Audience familiar with Haskell’s monadic computation may find that this return and to syntax look like return and >>= (bind) operators of monads.
In fact they are related. We will see this later, by way of denotational semantics using monads.
We also have thunk and force syntax. Thunk captures a computation and turns it into a value. Force gives the computations which evaluate these captured thunks. They don’t have counterparts in Haskell.
This figure describes how to embed call-by-value calculus to call-by-push-value calculus.
Note that because of to syntax, we can ensure that in evaluation of a function application, N is evaluated before the substitution occurs.
This figure describes how to embed call-by-name calculus to call-by-push-value calculus.
In contrast to call-by-value calculus, in evaluation of a function application, N is captured in a thunk and directly passed to M.
To summarize, we introduced a calculus named call-by-push-value. We have embedding of call-by-value and call-by-name calculi to call-by-push-value.
(7:12)
The categorical semantics of pure typed lambda calculus is Cartesian-closed categories, like Sets. The semantics of types are objects, the semantics of terms are arrows. Here “pure” means there are no side effects like printing characters, error handlings, stateful computations and continuations.
Then we want denotational semantics of non-pure lambda calculus. There is a well-known approach to this using monads.
It is widely accepted that Kleisli categories Kl(T) for a monad T give semantics of CbV calculus. This is due to Moggi’s work. Types are objects in Kl(T), in other words, objects in C. Terms are mapped to arrows in Kl(T).
This is the call-by-name counterpart of monadic semantics. It is known that Eilenberg-Moore algebras give semantics of call-by-name calculus.
Semantics of call-by-push-value is given by an adjunction between Eilenberg-Moore categories. Semantics of values are objects in C, and semantics of computations are objects in EM(T), in other words, Eilenberg-Moore algebras.
Moreover, this embedding preserves semantics.::
Semantics of call-by-push-value is given by an adjunction between Eilenberg-Moore categories.
To summarize, the embedding of CbV and CbN preserves denotational semantics. The monad of computation is decomposed into adjunction.