5.2 The HH and Applicative Languages
5.2.4 Applicative Structures
The technique that is described in this chapter relies on combinatory logic, instead of the more common approach of using supercombinators [Hug82]. The reason for this is that, while supercombinators are good for compiling, for finding specific instances of common point-free primitives (e.g. function
5.2. THE HHAND APPLICATIVE LANGUAGES 155
composition) is simpler when working with a small, fixed set of combinators. Applicative operators have been used for concurrency and parallelism before. Marlow et al. [MBCP14] define Haxl, a concurrency abstraction built on top of Haskell Applicative Functors, that allow implicit concur- rency to be extracted from Monad and Applicative instances. Unlike their approach, which is based on the implicit parallelism of the <*> applica- tive operator, our approach uses applicative structures to discover potential instances of parallel patterns.
Combinatory Logic
Combinatory logic [Sch24, Cur30] was originally defined as a notation for mathematical logic, and it was later used as a model of computation [Bar84]. Combinatory logic is based on the notion ofcombinators: higher-order func- tions that are defined in terms of function application, and other previously defined combinators. Common examples of combinators are the S, K and I
combinators:
Sf g x=f x(g x) Kx y=x Ix=x
TheScombinator is a generalised form of application, whereSf g xapplies
f to g, after passing x to f and g. The K combinator is the constant
combinator. The constant combinatorKapplied to somex,K x, is a function which always returns x, given any input. Finally, the I combinator is the
identity combinator, which always returns the same input unaltered. Note that some combinators could be implemented in terms of other combinators. For example, the I combinator is extensionally equal to S K Kand S K S.
Function composition Two additional combinators, B and C, originally introduced by Schönfinkel [Sch24] and rediscovered by Haskell Curry [Cur30], capture different notions of function composition. TheCcombinator can be thought of as a “swap function”, that exchanges the order of the arguments that are passed to f. The argument to C f x is passed to f, which is then applied to x:
f ◦g =λx.f (g x) =[x](f (g x)) =S(Kf) (S(Kg)I) =S (Kf)g
Figure 5.4: Function composition, represented using the S and K combina- tors, derived using bracket abstraction.
Cf x=Sf (K x)
It is possible to defineCin terms ofSandKas well. The resulting expression is, however, more complex than that of the B combinator, and it is not of interest for the purposes of this chapter.
The B combinator is equivalent to the usual notion of function compo- sition, and the technique on this chapter relies on finding instances of this combinator in the source code.
f◦g =Bf g =λx.f (g x)
Since it can be defined using S and K combinators (see Figure 5.4 on page 156), the technique that we describe in this chapter relies on find- ing the following instances of the S and K combinators.
B=S(KS)K
Bf g=S(KS)K f g= (KSf) (Kf)g =S (K f)g
To associate terms inHH, we will rely on standard techniques for trans- latingλ-expressions to combinator expressions. An algorithm for translating from λ-expressions to combinatory logic is generally known as abstraction elimination [Bar84]. One of the possibilities for performing abstraction elimination is through bracket abstraction, which is a process that takes a variable x, an expression E, and produces an expression, [x].E that is extensionally equal to λx.E. An example of this is Turner’s bracket ab- straction [Tur79]:
[x]x =I [x]y =Ky
5.2. THE HHAND APPLICATIVE LANGUAGES 157
Applicative Expressions
Generally, combinator expressions are built by using only a set of prede- fined combinators and application. Expressions that share this pattern are generally called applicative, and this has been captured by the HaskellAp- plicative type class. In this chapter, the term ‘applicative expressions’ is used to refer to terms defined using the specific syntax in Definition 5.2.1.
Syntax of Applicative Expressions
The syntax of applicative expressions, with atomic termsM, and primitive operations P, is defined as follows.
5.2.1 Definition | Syntax of Applicative Expressions.
M ∈ M p∈ P
ai ∈ AM ::= [M] | p | hin | @nm a1 · · · am
Applicative expressions are parameterised by the domain M. If M is some term in domain M, then [M] is an atomic expression. If pis in the domain of primitive operations, p ∈ P, then p is an applicative expression. The applicative expressionhinis equivalent tonapplications of theKcombinator,
i.e. hxin =
ntimes
z }| {
K (. . .(Kx)). In other words, hin is the composition of n K
combinators. If n = 0, then hi0 =I. Finally, the combinator@n
m a1· · ·am
is the application of m terms, in a context ofn elements, and is similar to the Φn
m defined by Curry et al. [CFC58]. Applying a @nm combinator to n
inputs is equivalent to applying the n inputs to the a1···m terms, and then
applying the resulting a2···m to the resulting a1. Since we require@nm to be
fully applied, the subscript is generally omitted.
@0 (@na1· · ·am)x1· · ·xn
=@0 a1 x1· · ·xn(@0 a2 x1· · ·xn)· · ·(@0 am x1· · ·xn)
The @ applicative structure can be defined in terms of S and K. We show below the case for @n
2, since @nm can be defined by nesting@n2:
@n= I if n = 0 S◦(S (K @n−1)) if n >0
5.2.1 Lemma λx1 · · · xn.M N ≈@n(λx1 · · · xn.M) (λx1 · · · xn.N) Proof By induction on n. Case n = 0. M N =@0 M N =IM N =M N. Case n =m+ 1. λx x1 · · · xm.M N ≈ {Induction Hypothesis} λx.@m(λx1 · · · xm.M) (λx1 · · · xm.N)
≈ {Apply Bracket Abstraction}
[x].@m(λx x1 · · · xm.M) (λx x1 · · · xm.N)
≈ {Unfold Bracket Abstraction}
S(S(K@m)(λx x1 · · · xm.M)) (λx x1 · · · xm.N)
≈ {Fold Function Composition}
(S◦(S(K@m)))(λx x1 · · · xm.M) (λx x1 · · · xm.N)
≈ {Fold Definition of@}
@m+1(λx x1 · · · xm.M) (λx x1 · · · xm.N)
Notation and Assumptions
The work in this chapter uses the following notation and assumptions. The usual juxtaposition, a1 a2, is used instead of explicitly writing @0 a1 a2.
Recall that the composition of n K combinators is written hin. Applying n
K combinators to an expression, hin a, is written hain. The notation haii m
stands for @i
m+1 haii. Since the combinators @ are required to be fully
applied, the subscript is omitted.
5.2. THE HHAND APPLICATIVE LANGUAGES 159
The composition operation is defined in terms of @ and hi1: a◦b =hai1 b
The work in this chapter is developed modulo associativity of ◦:
a◦b◦c =a◦(b◦c) = (a◦b)◦c
=hhai1 bi1 c =hai1 (hbi1 c)
The following notation is used for sum and product types. Recall that &nis
an-tuple constructor, i.e. &nx1· · ·xn is a tuple ofn elements, (x1, . . . , xn).
The usual product morphism is defined as follows:
Mn a1· · ·an=h&ni1na1· · ·an
The expression Mn a1· · ·an is a function that takes one argument, and
returns the n-tuple that results from applying the ai to the input:
(Mn a1· · ·an)x = (a1 x, . . . ,anx)
The product functor is defined in terms of the product morphism and pro- jection operations.
×n a1· · ·an =Mn (a1◦π1)· · ·(a1◦πn)
The expression (×n a1· · ·an) is a function that, when applied to a tuple
(x1, . . . , xn), it returns the tuple (a1 x1, . . . ,an xn). Finally, the sum functor
is defined in an analogous way to the product functor:
+n a1· · ·an =On (inj1◦a1)· · ·(injn◦an)
The expression (+n a1· · ·an) is a function that takes some inji x, for
i∈[1· · ·n], and returns inji (ai x).
Remark By using a Church-encoding of sums and products, primitive op- erations could be entirely represented using applicative expressions:
&i =@i+1|i0 | 0 i · · ·| i−1 1 Oi =@i+1 |i0 | 0 i · · ·| i−1 1 πji =@1 I|ij−i inj j i =@ j+1 |i j−i | 0 j
However, this representation adds no benefit for the purpose of parallelising patterns of recursion. In order to reason about patterns of recursion and parallelism, the usual product and sum combinators,MiandOi, expose more
structure than directly working with the church encoding of those primitive types. In the rest of this chapter, tuple constructors, projections, sum injections and either combinators will be considered primitive operations, as shown in Figure 2.5 on page 42.