0% found this document useful (0 votes)
5 views7 pages

Functional Programming Design Pattern

This document provides an overview of functional programming (FP) design patterns for object-oriented programmers, highlighting the paradigm's growing acceptance in mainstream programming languages. It discusses key concepts such as Turing machines, lambda calculus, immutability, pure functions, and higher-order functions, emphasizing the benefits of FP in achieving concise, safe, and modular code. The document also contrasts imperative and declarative languages, illustrating how FP can enhance non-functional design in real-world applications.

Uploaded by

Charles Kagiri
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
5 views7 pages

Functional Programming Design Pattern

This document provides an overview of functional programming (FP) design patterns for object-oriented programmers, highlighting the paradigm's growing acceptance in mainstream programming languages. It discusses key concepts such as Turing machines, lambda calculus, immutability, pure functions, and higher-order functions, emphasizing the benefits of FP in achieving concise, safe, and modular code. The document also contrasts imperative and declarative languages, illustrating how FP can enhance non-functional design in real-world applications.

Uploaded by

Charles Kagiri
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

1

Functional Programming Design Patterns for Object


Oriented Programmers - A Brief Overview

I. I NTRODUCTION in real code. Finally, I will illustrate usage of functional


patterns in real-world, non-functional code to demonstrate
The functional programming (FP) paradigm has seemed how its patterns can be used to improve non-functional design
to be, for quite some time, a subject mostly reserved and how FP ultimately manifests itself as a different way of
to academic settings and researchers interested in the tackling computational problems.
intersection of mathematics and computing. Little would be
talked about it among software developers, and languages II. A N OVERVIEW ON C OMPUTATIONAL M ODELS
would provide little to no native support for FP constructs.
This scenario has been changing, and in recent years, major A. Semantic and Representation
recognition and adoption of FP paradigm has been seen on To begin this section, I ponder a classical question trivial to
mainstream languages and frameworks. computer scientists: what is a computer? Whenever I ask this
question or a similar question to my computing science peers,
On Java JDK 8, released in March 2014, lambdas were I get “a computer is a Turing Machine (TM)” as an answer.
introduced [1]. These are, as described in the release That answer is correct, but it is not the only possible answer.
notes, “instances of single-method interfaces” [1]. On June As we will see, computers are ore precisely defined in terms of
2015, ECMAScript 6, Javascript’s standard, defined arrow what they are capable of doing rather than what they are, and
functions [2], allowing anonymous functions, or functions this might imply in vastly different approaches that attempt to
with no associated identifiers, to be passed as arguments. capture the notion of computation. Let’s briefly explore that
Although Java and Javascript might refer to these newly concept and see how that lead us into functional programming.
introduced features with jargons appropriate to the paradigms
and features each already supports, both features accomplish As stated in [6], a problem is computable iff it is Turing
the same, and we will go over such details in subsection III-B. computable. Furthermore, a Turing computable problem is a
problem that can be solved by a TM [7]. Let’s disregard the
Newer languages and frameworks went beyond introducing FP notion of efficiency here and assume we have infinite time
language constructs and embued its paradigms in their design and space for computing so we can focus on the general
and native capabilities. React, for instance, is admittedly idea of computability. The takeaway here, whatsoever,
inspired by FP paradigms [3]. One clear indication of this is that computable problems is defined in terms of TMs.
fact is how components are decoupled from states just like This is an important observation for the point I will soon make.
functions in FP should be stateless and should not produce
or be influenced by side-effects. Scala [4] and Kotlin [5], for A TM is defined as a device that is capable of carrying
instance, provide native support for higher-order functions out one among a finite set of instructions at a time whose
(see III-C), a functional programming construct that is often instructions involve transitioning among machine states,
not supported in “traditional” imperative languages like C. moving right or left along an infinitely long one-dimensional
tape, and reading and writing to and from that same tape.
Given these examples, it should be clear how FP has Note that this is an overly simplistic definitions for the sake
become almost ubiquituous among programming languages, of this discussion, and is based off [7], which provides a more
and how, at some point, even a software developer that is rigorous mathematical definition. This definition does not
completely oblivious to the notion of FP has already probably depend on any other notion of computers or computations,
leveraged some of its patterns to achieve something that and is effectively capable of providing the field of computing
otherwise require a convoluted, unsafe, or inefficient solution. with the necessary axiomatic foundations for expanding our
On the other hand, a software developer which understands knowledge on computation. But why is a TM the defining
FP and its patterns can benefit from its capabilities to achieve concept of a computer?
a significantly greater degree of conciseness, safety, and
modularity that cannot be easily achievable otherwise. When Turing firts defined a TM, it did not intend to
satisfy any more primitive axioms or conditions which
In this document, I will start by introducing some basic attempted to define a computer. Rather, the TM attempted
theoretical foundations that should foster the reader’s intuition to capture the primitive operations which permitted the
and allow for later conceptual connections to be made. Next, computation of all problems deemed to be computable, and
we will go over some terminology and functional patterns that this definition has managed to withstand the trial of time.
should suffice for the reader to recognize functional patterns The TM is intuitive and relatable to human’s capability of
2

computing problems. Furthermore, all problems known to be details on the definitions of numbers in λ-calculus and on the
computable could be computed by TMs, and all problems conversion rules).
known to be uncomputable could not be solved by any TM
[7]. Furthermore, modern-day computers build in accordance In λ-calculus, one calculates a function on an integer
to the von Neumann architecture since the EDVAC were by applying those conversion rules until a function equivalent
inspired by the notion of finite universal TMs [8]. All these to the resulting integer is produced. Thus, in some sense,
reasons seem to explain why TMs are deemed as the de facto if you have a λ-function, you can “effectively calculate” its
definition of a computer. result when applied on an integer by performing a finite
number of conversions. Conversely, Church defines a function
Note, in the previous paragraph that the motivation behind the on positive integers to be “effectively calculable” if it can be
definition of a TM are problems deemed to be computable, defined as a λ-function [6], which implies that it should take
and without them, the TM would make no sense. In that a finite number of steps to arrive at its result. Furthermore,
manner, even though the definition of a TM does not depend through the Church-Turing thesis, Allan Turing also proved
on any more primitive notion of computers or computation, that every “effectively caculable” function is also computable,
it is relevant as effect of its ability to solve problems deemed and vice-versa [10].
to be computable. If the TM was not capable of solving all
problems deemed to be computable, it would likely not be Note how each of these terms were defined by their
considered a computer at all. Note that this scenario wouldn’t respective constructs: “Turing computable” are problems that
cause the definition of a TM to be false. Rather, its operations can be computed by TMs, and “effectively calculable” are
would only allow it to solve a subset of the problems deemed functions that can be λ-defined. In that manner, at the same
to be computable. But how good is a computer that can’t solve time that each term is equivalent, they are independent of
problems that we know we can compute? Thus, a TM only each other and are defined without requiring the other one to
makes sense given the existence of such computable problems. exist.

Now, you might have noticed something. I have first Similar as to how they are independent, they are also
mentioned that computable problems are defined in terms of equivalent in that they capture the same idea, but through
a TM, and even though the definition of a TM precedes the different representations. It could be said that Turing takes
definition of a computable problem, it only makes sense given on a more “procedural” approach on computability, perhaps
the existence of computable problems. This might seem as a mimicking human’s computational process, while Church
circular definition, but in reality, this is the duality between takes on a more mathematical approach.
semantics and representation. For one to become aware of an
idea, one must first capture it through some definition. At the Although there have been lots of details on both computational
same time, a lexical definition only makes sense in light of a models that have been left out, a reader interested on the topic
semantically valid idea. is encouraged to look at the references in this paper look at the
references of these references, and deepen their understanding
Another example where this phenomenon is clearer is about these computational models. Nonetheless, my main
when we look at Pythagora’s theorem. Without some goal behind this theoretical background was not to thoroughly
representation like Pythagora’s equation, the idea captured cover these computational models, but to provide the reader
by the mathematical equation is so vague we might not with a perspective on this duality which constantly manifests
even be aware of its existence. On the other hand, if the itself through FP. Thus, have in mind that even though we
idea was false, the formula would have no useful meaning. will cover applications of FP in the context of imperative
And even though we tend to represent Pythagora’s theorem OOD, you can think in terms of FP as far as possible until
through the classical equation c2 = a2 + b2 , many other you reach the primitives upon which your solution depends
equivalent representations exist. Now, we can represent on which are defined in terms of imperative programming.
Pythagora’s theorem through different representations, but
what if we could grasp the notion of computability through
other representations? That’s where Lambda Calculus comes C. Imperative VS Declarative Languages
in. Now that we covered TM and λ-calculus computational
models, I invite you to think of a procedural language like
C as a realization of a TM. Think of how it describes the
B. Different Representation of Computers procedures to solve a problems similar to how a TM describes
Lambda Calculus was introduced in the form as we know the procedures to compute a problem, except that C does so at
it by Alonzo Church as a means to construct a formal system a higher abstraction level. This similarity is not a coincidence.
which could define and reason about mathematical objects The language is intended to replicate the computational model
[9]. This formal system defines every mathematical object that inspires it, and a TM is not only a good candidate to be
in terms of functions, including numbers themselves. It also followed in reason of being the computational model most
defines certain conversion rules (or substitution rules) which computing scientists are familiarized with, but also because
allows derivations to be performed (see section 4.2 on [7] for it is the same computational model traditional computers
3

mimick, thus being easier to implement and often having E. Partial Application
better performance as a result of a more straightforward
Partial application is a concept of lambda calculus which
implementation.
defines a function as another functions with partially applied
arguments. For instance, if we have the function sum(a,b)
A procedural language is a type of imperative language. An
:= a + b, we can define sum2(a) := sum(a, 2) s.t.
imperative language imperatively describes the computer how
sum2(3) = sum(3, 2) = 3 + 2.
to solve a problem. Object-oriented programming is another
example of an imperative language, but now we have the idea
of objects. On the other hand, FP is a functional language
F. Closure
which declares the program in terms of functions and is one
type of a declarative language. Declarative languages, on the Closure is a concept already present in procedural lan-
other hand, declares what needs to be executed, but does not guages, but which must be resignified in the context of FP. Clo-
imperatively describe how [11]. Simiarly to how a procedural sure is the determination of a variable’s value by the context
language “realizes” a TM, a functional language “realizes” of where the functions is defined. For instance, we may have
λ-calculus. something like fooProducer(x) := foo() := x, s.t.
fooProducer is a one-argument function that produces
The major takeaway in the definition and distinction a zero-argument function that returns the value passed to
between these language categories is what kind of syntax fooProducer. In this case, foo is able to determine the
you should expect from each. Idiomatic FP should not value of x because foo and x are both defined in the context
be describing procedures to solve a problem, but rather a of fooProducer.
series of function applications that should take on as much
a mathematical format as possible. Of course, this is not
entirely possible since you might find yourself having to define G. Currying
some primitive language constructs in terms of imperative
Currying is similar to partial application in that it sets the
programming, or having to perform some computations not
arguments of a function, but in this case, it does so by setting
easily expressed mathematically, but these should be avoided
one argument at a time by returning a one-argument function
as much as possible, and when cannot be avoided, be clearly
for each argument until all arguments are set. Here are a
compartimentalized to avoid “contaminating” functional
few examples for a one, two, and three argument functions
code by causing side-effects where not expected, impairing
respectively:
readability or causing other undesirable effects.
• oneArg(x) := x, then oneArgCurry(x) := ()
:= oneArg(x)
III. F UNCTIONAL P ROGRAMMING C ONCEPTS
• sum(a, b) := a + b, then sumCurry(a) :=
A. Immutability (b) := () := sum(a, b)
Immutability is key to functional programming, and al- • sumAndMult(a, b, c) := (a + b) * c, then
though it might be difficult to get around, it provides with sumAndMultCurry(a) := (b) := (c) := ()
several benefits which will later be discussed. Immutability, := sumAndMult(a, b, c)
as the name says, implies in no variables being able to change Note that currying is only possible by leveraging closure.
values once defined.

B. Pure Function H. Laziness


Pure functions are functions that, 1) will produce the same Laziness is the execution of a computation only when
output given the same input, and 2) it has no side-effects. strictly necessary and not at the time of definition. For in-
In this way, functions will be effectively deterministic and stance, if you define a variable A to be the result of a complex
predictable, always producing the same results for the same computation, that computation will not be performed until we
inputs [12]. get to a point in the program where we need to know the value
of A, such as for printing it or writing it to the disk. On the
other hand, if A is only used when defining another variable B,
C. Functions as First-Class Citizen
but for whatever reason, B is never needed, then A will never
A function is a first-class citizen if it has support for get evaluated as well [12].
operations usually associated with values, including 1) being
passed to functions, 2) being returned by functions, and 3)
being assigned to variables [13]. I. Memoization
Is the caching of a function result for a given input so that
D. Higher-Order Function (HOF) it does not need to be recomputed for that same input. The
Higher-order funtions are functions take one or more func- memoized values should always be the correct ones for pure
tions as arguments, or return a function, or both [13]. functions.
4

J. Tail Recursion
Tail recursion is a technique to run a call of a recursive The way the Serializer works is by mapping class names to
function after returning from the calling function. This is often a call to the object constructor, and this mapping is done by
how imperative-programming loops and iterative functions are the Serializer which is invoked by the decorator. But here’s
represented in idiomatic FP. This feature is, unfortunately, the catch: the constructor the decorator function takes has
not natively supported by most imperative languages which no information on its own arguments. This is a problem
support FP. Below is one example of a function that computes for objects that require arguments to be constructed, and
Pn
i: imposing restrictions on the class design is likely to lead to
i=0
bad class design, and what would go against the purpose of
tailSum(i, n, accumulator): a serializer that was meant to be flexible and generalizable.
if i == n:
return accumulator The solution to this problem was a multi-argument decorator.
else: The multi-argument decorator takes in a variable number of
return tailSum(i+1, n, accumulator+i) arguments and returns a function that takes in a constructor
and performs a side-effect. Thus, it is a higher-order function
sum(n): that returns a higher-order function. By leveraging closure
tailSum(0, n, 0) and partially applying the constructor, I am able to do the
task. Below is the code for the decorator:
IV. R EMARKS ON S KIPPED C ONCEPTS
Note that there is more to FP than the concepts here
presented, even though the most used FP techniques in OOD 1 export function s e r i a l i z a b l e ( . . . args
(from my experience) have been described above. For a more : any [ ] ) {
comprehensive resource on functional patterns, see Greg 2 return ( constructor : Function ) =>
Baker’s notes on FP [14] or refer to a FP resource, such as {
Haskell’s wiki [15]. 3 let objectSerializer =
ObjectSerializer .
Note as well that I have skipped discussions on type getObjectSerializer () ;
theory [16], a mathematical theory from which FP borrows 4 l e t c o n s t r = c o n s t r u c t o r . bind ( null
many concepts to deal with types in a rigorously defined , . . . args )
manner and cope with certain situations not clearly defined 5 objectSerializer .
by λ-calculus alone. I believe that it would be more benefitial registerSerializable (
to deepen the discussion on FP in this document rather than c o n s t r u c t o r . name , c o n s t r ) ;
introducing the idea of type theory without being able to 6 }
properly expand on it. Nonetheless, I encourage interested 7 }
readers to do their own research on the topic as some
understanding from the topic can be very benefitial for the
FP programmer. Note how in line 2 we begin defining an anonymous function
that is going to be returned by the decorator, and in line 4,
V. A PPLICATIONS OF FP IN H AITI H OSPITAL P ROJECT inside the anonymous function, the method bind is called,
setting this to be null inside the constructor (there is no
Now, I would like to go over some FP applications in a real-
this object prior to its construction) and partially applying
world Typescript OOD project, showing how some FP tech-
the multiple arguments to the constructor, which can be
niques can be applied even in a project that follows a different
passed in the nested function thanks to closure. Through this
programming paradigm. For the following illustrations, I will
partial application, a zero-arguments constructor is returned,
be using code from the Haiti Hospital project [17], commit
which can be called at any moment to construct an object
c0569944c6820b65a5326811c2d4c4345ef1e63f. I
with the arguments partially applied. Of course, this design
will try to provide with some snippets of code in this docu-
should only work if the arguments passed to the decorator
ment, but the commit should be referred to for further context.
correspond to the appropriate arguments that construct an
instance of the object.
A. Example 1: Partial Appliction of Functions
The Serializer is an experimental class at the time of this This is one example of a feat achieved by FP that probably
writing which is capable of serializing any object that is could not be achieved otherwise. Partial application of
decorated with the @serializable decorator. A decorator functions allows developers to, in a way, bring down the
is a function that takes in a constructor and performs some type of arguments to a least common denominator, when
side-effect with it. Decorator functions are run when the one exists. In this case, the least common denominator of
class is declared, and thus should run before any usage of arguments is zero (no arguments), which can be achieved by
that class. The class is located in the common folder of the partially applying all arguments, as it is in fact done in the
front-end. code above.
5

B. Example 2: Higher Order Functions for Modularity unknown>>;


Another great usage of higher order functions is to 6
enable behaviour modularity. In all kinds of programming 7 / / C o n s t r u c t o r , g e t t e r s and s e t t e r s
paradigms, since the traditional procedural programming 8
paradigm, we are often used to modularizing and structuring 9 public readonly addValidator = (
data, but when it comes to behaviour, the further the typical v a l i d a t o r : ( a n s w e r ? : T ) =>
developer unaware of FP goes it extracting functions on V a l i d a t i o n R e s u l t <unknown >) : v o i d
procedural languages or modularizing methods according to => {
a hierarchical structure as enabled by OOP. 10 t h i s . v a l i d a t o r s . push ( v a l i d a t o r ) ;
11 }
While method overloading and calls to super-class methods 12
are enabled by OOP, being able to only modularize behaviour 13 p u b l i c r e a d o n l y v a l i d a t e = ( ) : Array
as far as a hierarchy between types allow is rather limited. <V a l i d a t i o n R e s u l t <unknown>> => {
One example where this limitation was clear was in the 14 return this . validators
design of what is the current class Question, which is 15 . map ( ( v a l i d a t o r : ( a n s w e r ? : T ) =>
found in the common directory of the front-end. V a l i d a t i o n R e s u l t <unknown >)
=> v a l i d a t o r ( t h i s . a n s w e r ) ) ;
The Question class is supposed to represent a user- 16 }
defined question of some type. The answer of that question 17 }
must be of that type, and each particular question might Although Question is abstract because I intend this class
have further semantic limitations to what is considered a to have one implementation per answer and ID type, the
valid answer. For instance, if the question is “what is your validation behaviour is defined dynamically. Thus, if you
age?”, then a negative number should not be allowed. The have, for instance, a class NumericQuestion extends
responsibility of making this validation could be left to the Question<number, number>, then the fact that one
developer which would use this library, but since questions in instance of a NumericQuestion determines positive
reality do have semantical constraints, the answer validation integers as valid answers while the other instance only allows
was deemed as a part of the responsibilities of the question. even answers does not imply in them being different class
types.
One way to solve this problem is by having Question be
an abstract class and have a method validate that must The behaviour modularity provided by higher-order functions
be implemented. In that manner, the developer holds the and proper usage of functional patterns is, perhaps, the most
responsibility to implement the class and define all validation manifestable advantage of FP in imperative programming and
behaviour inside that method. But I believe that this design possibly one of the most valuable benefits as it allows code
has some issues: 1) I believe in that manner we would be to be abstracted to an extent not previously achievable.
over-specifying the type of the classes. That is, there would
be a class implementation for each particular validation
behaviour. 2) It is verbose. 3) It would tightly couple the class
to the dependencies used in the validation implementation. C. Example 3: Declarative Syntax
In the code of the method searchById(id: ID) of
The discussed approach might be the correct approach QuestionTable, we have a clear example of how FP
in OOD, and if all the considerations I deemed as problems syntax should look like in OOD. The method in question
might be acceptable under that approach, then I cannot help searches through a two-dimensional array of TableCells,
but to find that such situations are clear shortcomings of a generic class defined as class TableCell<ID, T,
OOD. My solution to this problem is to make Question QuestionType extends Question<ID, T>>, and
accept one or more functions that take in the type of the attempts to look for a QuestionType with the given id.
answer and return a boolean representing the decision on Below is the code for the method:
whether the answer is valid or not. In that manner, all of the
previous issues are avoided, and the developer only has to 1 p u b l i c r e a d o n l y s e a r c h B y I d = ( i d : ID ) :
worry about defining the validation behaviour for Question. Q u e s t i o n I t e m <ID> | u n d e f i n e d => {
Below is the code for Question: 2 return this . questionTable
3 . reduce ( ( questions1 , questions2 )
1 e x p o r t a b s t r a c t c l a s s Q u e s t i o n <ID , T> => [ . . . q u e s t i o n s 1 , . . .
e x t e n d s Q u e s t i o n I t e m <ID> { questions2 ])
2 p r i v a t e r e a d o n l y prompt : s t r i n g ; 4 . map ( q u e s t i o n C e l l => q u e s t i o n C e l l .
3 p r i v a t e answer ? : T ; getQuestion () )
4 5 . f i l t e r ( ( q u e s t i o n I t e m ) =>
5 p r i v a t e r e a d o n l y v a l i d a t o r s : Array <( q u e s t i o n I t e m . g e t I d ( ) == i d ) [ 0 ] ;
a n s w e r ? : T ) => V a l i d a t i o n R e s u l t < 6 }
6

Note in the code above 1) the chain- VI. F INAL R EMARKS


ing syntax (that is, a syntax like ob- In this document, we have discussed the duality between
ject.procedure1(...).procedure2(...)...) semantics and representation, how the Turing computational
and 2) how a function is anonymously defined as the model and λ-calculus are both ways of performing
arguments for each chaining operation even though we could computations, and we have briefly compared and contrasted
have instead passed pre-defined functions as arguments. The the languages representing these computational models. We
reduce operation defines the application of a function that went through some terminology and functional patterns
iteratively takes in two elements of a list and returns a single and how they can be applied in the context of imperative
element resulting from their computation until the entire list programming with a real-world example. It has been a long
is reduced to a single element. The map operations maps discussion, but a lot of important content could not be covered.
every element of a list to another element (possibly of another
type), and filter filters out objects that do not satisfy a The main goal of this document was to convince the
given predicate (a function that decides between true or false reader that FP, although seemingly restrictive, it does not
for any given input of the specifying type). limit in any way what can be computed, rather presents a
different and elegant way to compute problems. The treatment
Note how, although we still have to provide some description of behaviour as data allows for a level of abstraction to be
of the operations to be performed, they take a much more reached which allows the developer to focus on what should
declarative, mathematical syntax that resembles a composition be done rather than the how, allowing for more rigorous static
of functions rather than a step-by-step description of how checking, making the code more expressive and reducing the
to transform the input. This is the expected syntax of FP surface for bugs to occur.
in OOP, and one of the biggest advantages is the reduced
cognitive load as you abstract the computational process of Another important insight that is perhaps more adequate
manipulating the data structures and iterating through them to a discussion of type theory, but is nevertheless relevant
and focus only on the behaviour while also dividing the in FP and should be appreciated is that a program is safer
transformation into smaller, compartimentalized steps that are and more readable when it is more restrictive rather than
much easier to comprehend than lines of code describing the more permissive. If permissiveness is good, then strict typing
how, but not the what of what you are doing. is bad, and restricted control flow through if , for and
while statements are bad and we are better off with goto
branching. Strictness enforces clear contexts, readability,
exhaustive handling of cases, and valid computational states.
D. Remarks on Examples Having errors be statically caught is a valuable capability that
can avoid hours of infuriating debugging.
It should be noted that, due current limitations of
the Typescript language and the project, other important If the reader is interested in expanding their knowledge
illustrations of FP concepts cannot be here provided. For on FP, I invite them to learn a purely functional programming
instance, Typescript does not provide native support for lazy language like Haskell [18]. Although the language is not
evaluation, memoization, persistent data structures or tail widely used in industry, programming in Haskell will
recursion. Although all these features can be implemented surely provide solid foundations on functional programming
to support FP-like programming, this implies in developers and ultimately challenge the reader to compute through a
having to maintain these implementations or having to depend completely different computational model. Ultimately, even
on modules that implement them, which are options not as if the reader does not code a purely functional program, the
attractive as relying on natively supported operations. novel ideas presented by this computational model should
motivate the reader to think through a fundamentally different
Functional programming also comes along with some perspective from which all kinds of programming paradigms
type theory techniques not discussed here (functors, monads, and problem solving scenarios may benefit from.
etc.) which enforce rigorous definitions and type safety, and
although Typescript does a really good job on statically
enforcing some of these constraints, it still lacks some R EFERENCES
features, such as pattern matching or guarded expressions [1] “What’s new in jdk 8,” [Link]
[14]. [Link].
[2] “[Link]/6.0/,” [Link]
0.
In light of the lack of support for these operations in [3] “Design principles – react,” [Link]
imperative languages, FP cannot be thought of a way to html.
[4] “Functional programming — scala 3 — book — scala documentation,”
achieve a completely different programming paradigm. [Link]
Rather, it provides with means to achieve higher behaviour [5] “High-order functions and lambdas — kotlin,” [Link]
modularity and abstraction that can be implemented on top of docs/[Link].
[6] B. J. Copeland, “The Church-Turing Thesis,” in The Stanford Encyclo-
imperative primitives as it has been illustrated in the examples pedia of Philosophy, Summer 2020 ed., E. N. Zalta, Ed. Metaphysics
above. Research Lab, Stanford University, 2020.
7

[7] L. De Mol, “Turing Machines,” in The Stanford Encyclopedia of


Philosophy, Winter 2021 ed., E. N. Zalta, Ed. Metaphysics Research
Lab, Stanford University, 2021.
[8] B. J. Copeland, “The Modern History of Computing,” in The Stanford
Encyclopedia of Philosophy, Winter 2020 ed., E. N. Zalta, Ed. Meta-
physics Research Lab, Stanford University, 2020.
[9] J. Alama and J. Korbmacher, “The Lambda Calculus,” in The Stanford
Encyclopedia of Philosophy, Summer 2021 ed., E. N. Zalta, Ed. Meta-
physics Research Lab, Stanford University, 2021.
[10] A. M. Turing et al., “On computable numbers, with an application to
the entscheidungsproblem,” J. of Math, vol. 58, no. 345-363, p. 5, 1936.
[11] M. Gabbrielli and S. Martini, Programming languages: principles and
paradigms. Springer Science & Business Media, 2010.
[12] “Pure functions, laziness, i/o, and monads - school of haskell
— school of haskell,” [Link]
starting-with-haskell/basics-of-haskell/3-pure-functions-laziness-io.
[13] “Clojure - higher order functions,” [Link]
order functions.
[14] “Cmpt 383 lecture notes,” [Link]
[15] “Haskellwiki,” [Link]
[16] T. Coquand, “Type Theory,” in The Stanford Encyclopedia of Philoso-
phy, Fall 2018 ed., E. N. Zalta, Ed. Metaphysics Research Lab, Stanford
University, 2018.
[17] “drbfraser/hha-haitihospital: System for hospital departments to pro-
vide feedback and information to administrators.” [Link]
drbfraser/HHA-HaitiHospital.
[18] “Haskell language,” [Link]

You might also like