2. 1
What is Functional Programming?
● Functional programming is style of programming
in which the basic method of computation is the
application of functions to arguments;
● A functional language is one that supports and
encourages the functional style.
Opinions differ, and it is difficult to give a precise
definition, but generally speaking:
3. 2
What hell are you saying?
● Function are first class citizen (values).
● Recursion is used as only method of control. (No
selection/iteration statements)
● We avoid state mutation like hell: avoiding
change in place. Pure function.
● High order functions: A function that is
composition of functions.
4. 3
Function are first class citizen
● Function are things
● Composition is used everywhere
to create other functions.
5. 4
First Class: Iterative Code
IEnumerable<double> Iter(double max) {
for (double x = 0; x < max; ++x) {
if (x == 1) {
yield return Math.Pow(x, 4.0);
}
else {
yield return x * 2;
}
}
}
6. 5
First Class: Functional Equivalent
// We define functions.
Func<double, double> Superpower = x=> Math.Pow(x,4.0);
Func<double, double> Fortwo = x=> x * 2;
var list = Enumerable.Range(1,10);
// Now let’s compose things since we have
Func<double, double> Iter = list=>
list.Where(x=>x == 1)
.Select(Superpower)
.Union(list.Select(Fortwo));
7. 6
If Elimination: Iterative version
IEnumerable<TOutType> SimpleIfFunction<TInType,
TOutType>(IEnumerable<TInType> x, bool cond)
{
if (cond):
{
return function1(x)
}
else:
{
return function2(x)
}
}
Using a short circuit evaluation we can see:
(<cond> and function1()) or function2();
9. 8
If Elimination: Functional version
Pieces of the functional programmer toolbox:
- filter operator: from a sequence of values produce
a sequence that match a condition.
Haskell:
Input: filter (>5) [1,2,3,4,5,6,7,8]
Output: [6,7,8]
Filter C# = LINQ Where.
- map. Map is high order function, it applies a
function to each item of a sequence.
Map C# = LINQ Select.
In C# the map is expressed by LINQ Select.
Q: Is Correct to say that IfBranch and ElseBranch are two
imperative whiles with just one value?
10. 9
High order function
A high order function is function that uses a function
as parameter. A simple example using Dapper.
using System;
using System.Data;
using System.SqlClient;
public static ConnectionHelper
{
public static R Connect<R>(string connString,
Func<IDbConnection, R> command)
{
using (var conn = new SqlConnection(connString))
{
conn.Open();
return command(conn)
}
}
}
11. 10
High order function
Retrieve top 10 suppliers ordered by name.
using Dapper;
using Dapper.Contrib;
import static ConnectionHelper;
var connString =
"EngineName=EVENT;DataBaseName=EVENT;Uid=EVENT;Pwd=11278
1278";
Func<string, string> SelectSupplier = x =>
string.Format("SELECT TOP 10 * FROM Suppliers ORDER BY
Suppliers.Name”) ;
IEnumerable<Supplier> suppliers = Connect(connString,
c =>
c.Query(SelectSupplier());
Note: It is just an example. It is mandatory nowadays using
parameterized queries whenever we can.
12. 11
Pure Functions
A function is pure if it has no side effects.
public class Program
{
public static void Compute(List<int> nums)
{
Action task1 = () => nums.Sum();
Action task2 = () => { nums.Sort(); nums.Sum();
};
Parallel.Invoke(task1, task2);
}
public static void Main()
{
Compute(Range(-1000, 3000).ToList());
}
}
13. 12
Pure Functions
1. Is Compute a pure function?
public static void Compute(List<int> nums)
{
Action task1 = () => nums.Sum();
Action task2 = () => { nums.Sort(); nums.Sum();
};
Parallel.Invoke(task1, task2);
}
public static void Main()
{
Compute(Range(-1000, 3000).ToList());
}
Why? Functional dependency of
sort over sum.
14. 13
Pure Functions
Are those pure functions?
public double TripleMul(double x, double y, double y)
{
return x* y * z;
}
public DateTime MaxDeliveryDays(int days)
{
return DateTime.Now.AddDays(days);
}
15. 14
Pure Functions
A function has side effects when:
1. Mutates global state
2. Mutates its input arguments.
3. Throws exceptions
4. Perform I/O operations.
We want to separate those operations.
16. 15
In FP: We are pure and honest.
We want predictability from the input to the output.
This enables:
1. Parallelization - No Share State, No needs to
synchronize between cores/threads.
2. Lazy Evaluation - We evaluate values only when
needed, aka use of yield.
3. Memoization - Cache the result of a function.
A function is honest is respect its signature.
17. 16
In Depth on Lazy Evalution.
Lazy Evalutation .
static IEnumerable<int>
GetOddNumbers()
{
int i = 1;
while (true)
{
if (i % 2 == 1)
{
yield return i;
}
i++;
}
}
Eager Evaluation.
static int CountDown(int
i)
{
if (i <= 0)
{
return 0;
}
return CountDown(i-1);
}
18. 17
In FP we are very honest.
Is honest?
public static int
Divide(int x, int
y)
{
return x / y
}
Is honest?
public static int
Divide(int x,
NonZeroInteger y)
{
return x/
y.Value;
}
19. 18
In FP we are very honest.
Is honest?
public static int
Divide(int x, int
y)
{
return x / y
}
Is honest?
public static int
Divide(int x,
NonZeroInteger y)
{
return x/
y.Value;
}
20. 19
In FP we are very honest.
Is honest?
public static int
Divide(int x, int
y)
{
return x / y
}
Is honest?
public static int
Divide(int x,
NonZeroInteger y)
{
return x/
y.Value;
}
21. 20
In FP we are very honest.
Now your boss comes to you and wants a function to compute the risk of a car
accident.
Given the fact that the probability of accident is higher with people
with ages > 60, it has probability in Spain of 0.70, and with the rest
has a probability of 0.30, and the impact of your
company is 50, you may want to calculate a function R = P * I;
double CalculateRisk(int age)
{
if ((age <= 0) || (age => 120))
{
// crazy ages.
throw new ArgumentException($"{age} is not a valid age")
}
return (age < 60) ? 0.70 * 50 : 0.30 * 50;
}
Is this function honest?
This violate the contract that you agreed with your user in its signature.
Testability? Can i create a unit test just seeing the signature?
22. 21
In FP we are very honest.
Now your boss comes to you and wants a function to compute the risk of a car
accident.
Given the fact that the probability of accident is higher with people
with ages > 60, it has probability in Spain of 0.70, and with the rest
has a probability of 0.30, and the impact of your
company is 50, you may want to calculate a function R = P * I;
double CalculateRisk(int age)
{
if ((age <= 0) || (age => 120))
{
// crazy ages.
throw new ArgumentException($"{age} is not a valid age")
}
return (age < 60) ? 0.70 * 50 : 0.30 * 50;
}
Is this function honest?
This violate the contract that you agreed with your user in its signature.
Testability? Can i create a unit test just seeing the signature?
23. 22
Enforce honesty:
Eliminate Void Method
Fact of life: Most of the method with side effects / dishonest are void
method. The main problem with void from the functional point is that it breaks
composability.
Solution:
Everytime you need to return en empty value, just return a C# 7.0 value tuple,
in FP we call it Unit.
using Unit = System.ValueTuple;
public class Program
{
public static Unit MyFunctionWithoutVoid(int j)
{
return default(Unit);
}
public static void Main()
{
var f = MyFunctionWithoutVoid(MyFunctionWithoutVoid(3));
Console.WriteLine(f);
}
}
Makes sense?
24. 23
One billion dollar mistake.
Fact of life: Most of the method with side effects / dishonest are void
method. The main problem with void from the functional point is that it breaks
composability.
Solution:
Everytime you need to return en empty value, just return a C# 7.0 value tuple,
in FP we call it Unit.
using Unit = System.ValueTuple;
public class Program
{
public static Unit MyFunctionWithoutVoid(int j)
{
return default(Unit);
}
public static void Main()
{
var f = MyFunctionWithoutVoid(MyFunctionWithoutVoid(3));
Console.WriteLine(f);
}
}
Makes sense?
25. 24
One billion dollar mistake.
Facts of life:
1. Most modern imperative programming languages derived that and
other features from ALGOL
2. In C++03: set a pointer to null before freeing a memory
3. C#/Java accessing to a value set to Null => NullPointerException.
3. Return null from a function and the client uses that value.
Never do it, it is very dishonest.. The poor
man is still debugging..for this.
In Functional Programming with don't use null but the monad
MayBe(Haskell)/Option(F#). The Maybe monad represents
computations which might "go wrong" by not returning a value.
In C# 8.0 has been introduced NullableReference type
and the compiler does static analysis on null.
26. 25
One billion dollar mistake.
Example. A repository pattern in C#.
We start with an example. Suppose that you have a
repository:
public class SupplierRepository: IRepository<Supplier>
{
public async Supplier GetAsync(string id)
{
.......
}
}
Can you say just looking to this method that it can return null?
Suppose that the id doesn't exist in the data layer? The first
two options here are:
1. Return null (very very dishonest)
2. Throw an exception (dishonest - at least you can write
in the docs)
27. 26
Sleepy lazy copy cats.
In C# we have just the two options of the previous
slides. But we are good sleepy lazy copy cats.
Cats are notoriuous smart.
28. 27
Refactoring.
So we copy the same MayBe/Option concept from Haskell/F#.
I would prefer call it MayBe and create the monad for C# 7.0,
but we love C# 8.0.
// C# 7
public class SupplierRepository: IRepository<Supplier>
{
public async MayBe<Supplier> GetAsync(string id)
{
/*****/
}
}
// C# 8
public class SupplierRepository: IRepository<Supplier>
{
public async Supplier? GetAsync(string id)
{
/*****/
}
}
Now it is honest. We could establish the guideline that every
time we use a reference type as return we use maybe.
29. 28
Refactoring: MayBe Monad
public struct MayBe<T>
{
readonly bool isSome;
readonly bool T value;
private MayBe(T value)
{
this.isSome = true;
this.value=value;
}
public static implicit operator MayBe<T>(T value) =>
value == null ? new Nothing<T> : new Just<T>(value);
public static implicit operator MayBe<T>(Just<T> value)
=> new Maybe<T>(value.Value);
public static implicit operator MayBe<T>(Nothing none) =>
new Nothing<T>();
}
30. 29
Refactoring: MayBe Monad.
public struct Just<T> : MayBe<T>
{
public T Value { get; }
public Just(T value)
{
this.Value = value;
}
}
public struct Nothing
{
}
public struct Nothing<T>: MayBe<T>
{
public static Nothing Value { get; } = new Nothing();
private Nothing() { }
}
31. 30
Refactoring: Null is a bad guy.
public IsValidTrip(Trip possibleNull)
{
if (possibleNull == null)
{
throw new ArgumentNullException("IsInvalidNullTrip");
}
}
But the library NullGuard.Fody it will do it for us. How does
it works?
1. In implicit mode everything is assumed to be not-null,
unless attributed with [AllowNull]. This is how NullGuard has
been working always.
2. In the new explicit mode everything is assumed to be
nullable, unless attributed with [NotNull].
32. 31
Exception are dishonest.
As definition, an exception is something that corresponds to
an exceptional event.
So in this case we introduce a Either monad.
The Either type represents values with two possibilities.
A type Either a b is either Left a or Right b.
The Either type is sometimes used to represent a value which
is either correct or an error; by convention, the Left constructor
is used to hold an error value and the Right constructor is used
to hold a correct value (mnemonic: "right" also means
"correct").
33. 32
Exception are dishonest.
public struct Either<TOutcome, TError>
{
public Either(TOutcome data) => Successful = (true, data);
public Either(TError data) => Error = (false, data);
public (bool, TOutcome) Successful { get; }
public (bool, TError) Error { get; }
}
}
The Risk example becomes:
Either<double, string> CalculateRisk(int age)
{
if ((age <= 0) || (age => 120))
{
return new Either($"{age} is not a valid age");
}
var risk = (age < 60) ? 0.70 * 50 : 0.30 * 50);
return new Either(risk);
}
Now the function has no side effects, it doesn’t change state
and it is honest.
34. 33
FP Programmer Toolbox
Up to know we have seen some pieces of the toolbox of a
functional Programming.
We already seen some monads. We proceed with the FP
operators:
1. Filter - Mapped in C# from list.Where(cond) - Seen
2. Map - Mapped in C# from list.Select(function) - Seen
3. Reduce - Mapped in C# from list.Aggregate(function).
4. Bind - Mapped in C# from list.SelectMany(function) -
Monad.
35. 34
FP Programmer Toolbox - Reduce
Reduce.
Problem: We want reduce a list of values to a single value, i.e
the sum of items of the List.
var mapReduce =
Enumerable.Range(1,10).Select(x=>x*2).Aggregate((a,b) => a+b)
Aggregate can as well start from a seed.
var mapReduce =
Enumerable.Range(1,10).Select(x=>x*2).Aggregate(0, (a,b) =>
a+b)
In mapReduce we have the result of a Map + Reduce.
36. 35
FP Programmer Toolbox - Bind
Now we have to speak about Bind/FlatMap. We need a
function that can flatten different lists.A simple
implementation could be:
public static IEnumerable<R> Bind<T,R>(this IEnumerable<T>
ts, Func<T, IEnumerable<R>> f)
{
foreach(T t in ts)
foreach (R r in f(t))
yield return r;
}
This is functional equivalent to LINQ SelectMany.
37. 36
FP Programmer Toolbox - Bind
Homework. Suppose you have the list of neighbours, you want
to be nice and have the list of the pets of the neighbours.
38. 37
FP Programmer Toolbox - Monad
What is a monad?
Short answer: A monad is a computation builder.
It's a specific way of chaining operations together. In a
monad you do two things:
1. Writing execution steps.
2. Link together with the Bind function. The bind function
create a list from a step and feeds to another steps.
From the math point of view:
1. Existence of the identity.
2. Associative property in the function.
39. 38
FP Programmer Toolbox: Currying
Currying or Partial Evaluation. How does it work?
Suppose we have f(a,b)=b/a(7)
We want evaluate : f(4,8)
1. Replace 4 => We got f(4,b).
2. Got new function g(b) such date:
3. g(b)=f(4,b)=b/4(8)
4. Replace b with 8 and Game Over.
g(8)=f(4,8)=8/4=2(9)
In C# we can define a Curry Function:
public static Func<T1,Func<T1, Func<T2, R>> CurryEvaluate<T1,
T2, R>(this Func<T1, T2, R> func)
=> t1=> t2=> func(t1, t2);
40. 39
FP in Domain Design. Exercise.
Using functional principle we want to design a Money
Transfer Application where:
1. The core business logic is immutable.
2. The input is an IO.Monad
3. The output is an IO.Monad
A nice example of monads:
https://github.com/louthy/csharp-monad
Next time we will see the solutions.