Functional Programming in Scala
This blog post is the first one of a series of blog posts about Functional Programming in Scala. It is also a teaser for series of blog posts of about Reactive Programming in Scala.
Warning: Functional Programming and Reactive Programming are profound topics. Hopefully, you will be rewarded for your effort to read the blog posts.
Binding
You are, most probably, used to think of
 functions in terms of applying them to values
but, of course, you can also think of
 values in terms of binding them to functions
The method bind
below, defined in terms of apply
, formalizes binding
1 2 3 4 

Strictly speaking it is not necessary at all to introduce binding in Scala,
but, sometimes, bind
is more convenient to use than apply
, as illustrated below
1 2 3 4 5 

The method
bind
naturally associates to the left, while the methodapply
associates to the right, requiring the usage of parantheses.The Scala type inferencer naturally infers the type of expressions using
bind
, while it does not infer the type of expressions usingapply
, requiring the usage of type annotations.
Functional Programming
Here is some quote about Functional Programming
Functional Programming strictly separates
 the declarative description of computations
 the imperative execution of computations
So, what are the computations in this quote all about?
Computations of type One
Let’s get started with pure computations that, when executed, result in exactly one value
as defined by the following case class
1


Computations resulting in exactly one value are also referred to as computations of type One
.
When there is no danger of confusion, any kind of computation is simply referred to as a computation.
Constructing computations using mkOne
Computations of type One
can be constructed using mkOne
1


Agreed, introducing mkOne
is somewhat of an overkill,
but it is consistent with the way other kinds of computations are constructed
in this series of posts.
How are computations of type One
described?
Describing Computations of type One
Here is a computation of type One
that is described using mkOne
1 2 

A lazy val
is used to separate the description of the computation from its execution.
How are computations of type One
executed once they are described?
Executing Computations of type One
For the purpose of this series of blog posts,
executing a computation of type One
can be as simple as printing its value.
1 2 3 4 

Below, the computation of type One
is executed using execute
1 2 

The computation oneFoo
is defined as a lazy val
.
mkOne("foo")
is evaluated the first time that oneFoo
is executed.
When oneFoo
would have been defined as a def
, then
mkOne("foo")
would be evaluated every time that oneFoo
is executed.
For oneFoo
the difference does not matter
(apart from the fact that a lazy val
is more time efficient and less space efficient than a def
).
Sometimes the difference between a lazy val
computation and a def
computation does matter.
Declaring simple computations like oneFoo
and executing them as execute(oneFoo)
is,
of course, not the end of the story about computations of type One
.
Is there not a way to compose computations of type One
?
Composing Pure Computations of type One
The implicit class below defines two methods, bnd
and and
, that can be used to
describe more complex computations by, somehow, composing them from simpler ones.
1 2 3 4 5 6 

Although, strictly speaking, not necessary, bnd
and and
are defined in terms of bind
.
DSL for computations of type One
By now we have defined mkOne
, bnd
and and
 They constitute a declarative DSL for describing computations of type
One
We have also defined execute
 It constitutes an imperative DSL for executing computations of type
One
This section contains some examples on how to make use of those DSL’s.
All examples make use of the following add
function on strings
1


add
is a curried version of the +
operator on strings.
Let’s start with a computation using bnd
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 

The declaration of oneFooBar01
can, informally, be explained as follows
 evaluate the expression
"foo"
and bind the resulting value to the variablez
, and then  evaluate the expression
"bar"
and bind the resulting value to the variabley
, and then  result in the value obtained by adding
z
andy
Let’s continue with a computation using and
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 

The declaration of oneFooBar02
can, informally, be explained as follows
 evaluate the expression
"bar"
, and evaluate the expression"foo"
, and then  bind the resulting values to the variables
y
andz
, and then  result in the value obtained by adding
z
andy
Let’s finish with a simplified version of the computation using and
above
in which there are no variables used any more
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 

The declaration of oneFooBar03
can, informally, be explained as follows
 evaluate the expression
"bar"
, and evaluate the expression"foo"
, and then  result in the value obtained by adding their resulting values
You may ask yourself: this looks like much ado about nothing. We might as well have written the following code
1 2 3 

Well, in a way you are right: for pure computations resulting in exactly one value,
introducing mkOne
, bnd
and and
is much ado about nothing.
For more interesting kinds of computations, the situation is completely different.
Nevertheless it is already possible to formulate some interesting remarks.
Some remarks
First, a somewhat philosophical (and highly subjective) remark about syntax.
In some way, the DSL based code reads more natural from left to right
than the language based code. When initializing z
with "foo"
using val z = "foo"
,
first the expression "foo"
on the right hand side of =
is evaluated and
second the variable z
on the left hand side of =
is initialized with the resulting value.
Not very left to right indeed (in fact right to left instead).
Agreed, in another way, the DSL based code reads less natural because of all those curly braces.
Their nesting is usually limited since it is not a good programming practice to define
computations using large pieces of code (good programmers write small pieces code).
The curly braces also have an advantage: they clearly delimit the scope of the variables that are introduced.
Every disadvantage has its advantage (a quote of the Dutch soccer player Johan Cruijff).
Second, a remark about semantics.
The semantics of the language based code is defined by the language specification.
The semantics of the DSL based code is defined by you (in terms of the semantics of bnd
and and
).
This provides you with more flexibility.
Agreed, again, in the case of pure computations resulting in exactly one value,
there is not really a lot of flexibility for you to define bnd
and and
in a meaningful way.
For more interesting kinds of computations, the situation is completely different.
About abstraction
The method bnd
is more specific (concrete) than and
(the method and
is more general (abstract) than bnd
).
The method and
is more abstract than bnd
simply because the method and
can be defined in terms of bnd
(the definition of and
in terms of bnd
is referred to as the default definition of and
)
1 2 3 4 5 6 

For pure computations resulting in exactly one value, the two definitions are equivalent.
For more interesting kinds of computations,
and
can be given a definition that is not equivalent with the default definition.
About power of expression
The method bnd
is more powerful than and
(the method and
is less powerful than bnd
).
Below is an example that illustrates that the method bnd
is more powerful than and
:
when using bnd
the variable z
is immediately in scope, and can be used in the rest of the code,
for example, to decide, based on z
, how to proceed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 

The bottom line of all this is that, for most computations, the choice is yours
 you can go for less abstract, more powerful composition (and less implementation flexibility)
 you can go for more abstract, less powerful composition (and more implementation flexibility)
It is all about choosing the right level of abstraction. As a programmer, you should value abstraction: it is a tool to manage complexity.
Consider the difference between using bnd
and and
 the description of
oneFooBar01
requires the usage of variables  the description of
oneFooBar03
does not require the usage of variables
You may ask yourself: are there any other ways to compose computations?
Other ways to compose computations
The answer is yes, there is one other popular way to compose computations
1 2 3 4 5 6 

On the one hand, since >>>
can be defined in terms of bnd
(as shown above)
>>>
is more abstract (and less powerful) than bnd
.
On the other hand, since, in a way, and
can be defined in terms of >>>
(not shown in this post)
and
is more abstract (and less powerful) than >>>
.
The first series blog posts about functional programming is not dealing with this third kind of computation composition.
Reactive Programming
So far we worked with pure computations resulting in exactly one value. But, of course, there are also more interesting kinds of computations.
Reactive Programming, deals with two important computational features: failure and latency. Both should be dealt with for realizing responsiveness.
and
can be defined to deal with them in another way as bnd
.