Pragmatic Functional Programming


Programming is hard, and humans are bad at it

Scope


  • Introduction to functional programming
    • especially as it applies to C#
  • Terms and techniques
  • Practical advice for functional programming in C#

Brief C# primer


  • generics
  • Func<> and Action<>
  • lambdas and closures

Generics


class or method with a Type parameter in angle brackets


Consuming:

  • List<int> numbers;
  • var inf = Infinity<DateTime>();


Writing generic methods


Type parameter after the method name.

public List<T> Contain<T>(T a, T b)
{
    var result = new List<T>();
    result.Add(a);
    result.Add(b);
    return result;
}

Call the type whatever you want.

Can have multiple types, separated by commas.

Every instance of the type name refers to that type.

Generic classes


The entire class is parameterized by the type.

Put the type after the class name.

public class ConfigManager<T> where T : class
{
    private T config;
    public T GetConfig() { ... }
    private void LoadConfig() { ... }
}

Constraints go after the class (or method signature)
Don't parameterize each method.

Code as data


Action and Func are types used to refer to some method or delegate.


Action's return type is void

Func returns its last type parameter


example:

Func<string, int> takes a string and returns an int

Action<bool> takes a bool and returns void

Code as data


public bool IsHappy(Person p)
{
    return p.Happiness > 75;
}

Func<Person, bool> happyTester = IsHappy;
happyTester(bob);

Lambdas


A lambda is a shortcut for making code without making a method.

Func<int, bool> isAdult = (int age) =>{    return age > 17;};

equivalent:

Func<int, bool> isAdult = age => age > 17;

Closures


A closure is any lambda/delegate which "closes over" or "captures" things in its scope.

var limit = 0.04;Func<float, bool> aboveLimit = bac => bac > limit;

limit is a local variable, but aboveLimit captures it for its own use.

Even if limit goes out of scope, aboveLimit can still use it.

Closures in C# are by reference, so the captured values can be changed and those changes will be reflected.

What is Functional Programming?


programming by composing pure functions


both:

  • as a paradigm
  • languages that facilitate the paradigm

What is a paradigm?


style


informed by language

What are some examples?


  • imperative
  • object oriented
  • declarative
  • functional
  • etc

What's Functional Programming Like?


it uses functions

What's a function?


a "pure" function is a map of inputs to outputs



Big whoop


only inputs and outputs. no other work

no side effects

public void DoubleNumbers(int[] list)
{
    for (int i = 0; i < list.Length; i++)
    {
        list[i] = list[i] * 2;
    }
}

DoubleNumbers changes its input

Referential Transparency

No:
  • changing function arguments
  • accessing class members
  • changing a static variable
  • reading or writing to disk
  • talking over the network


That seems useless


Can I do anything at all?


You can compute values and return them.

Immutability


immutability: objects cannot change


Have you ever tried to do this:

string firstName = firstNameField.Text;firstName.ToLower(); //this does nothing

Generally everything is immutable in functional programming languages. This makes it easier not to change your function arguments!

First-class functions

functions as variables / values

public IList<int> YearsUntilDeath(IList<Person> people)
{
    Func<Person, int> death = (Person p) =>    {        return 70 - p.Age;    };
    return people.Select(x => death(x)).ToList();
}

If a function is a value...

pass a function as an argument

public string DecodeMessage(string message, Func<string, string> decoder)
{
    return decoder(message);
}

return a function from a function
public Func<int, int> GetEmbiggener()
{
    Func<int, int> embiggener = (int x) =>
    {
        return x * 100;
    };
    return embiggener;
}

Higher order functions


fancy name for a function that either:

  • takes a function as a parameter
  • returns a function

example
students.Select(x => x.Name);

signature of Select:
IEnumerable<U> Select<T,U>(this IEnumerable<T> source, Func<T,U> map)

Looping


Immutability means you can't change things.

Not even a loop index:  i++

Then how do you loop through an array?

Recursion.

public int Max(int[] nums)
{    if(nums.Length < 2) return nums.Head;
    var maxTail = Max(nums.Tail);
    return maxTail > nums.Head ? maxTail : nums.Head;
}

That's stupid


don't bother

not practical in C#

practice pragmatism

Type inference

C# has local type inference

 var x = 10;


functional programming languages usually do better

var list = [];
var person = new Person();
list.Add(person);


function Add(a, b) {
  a + b
}

Tuples


two or more values

public Tuple<string, Gender, FavoriteColor> WhoAreYou(){    return Tuple.Create("Ross", Gender.Male, Color.All);}

better support elsewhere

What are some functional programming languages?



  • Haskell
  • Clojure
  • Scala
  • F#


  • Lisp
  • Scheme
  • OCaml
  • Erlang

Evaluation models


expressions everywhere

public bool IsMoreThanTen(int n)
{
    if (n > 10)
        true
    else
        false
}


evaluate until nothing is left (inside-out)
"lazy" evaluation models
order is less important
parallelization is easier

Algebraic data types


discriminated union / tagged union


type Shape {  Circle(Point, float),  Rectangle(Point, Point)}

alternative to class hierarchies

Pattern matching


public float Area(Shape sh) {  match sh {    Circle(_, radius) => PI * radius * radius,    Rectangle(Point{x,y}, Point{x2,y2}) => (x2 - x) * (y2 - y)  }}

kind of like switch
destructuring
can have guards and wildcards
compile-time checking

What is functional programming?


programming by composing pure functions


in a declarative style


often using immutable values


usually with a rich type system

What's the point


simple things that compose well

easier to write reusable code

promotes correct code

especially effective in the small scale

promotes readability and testability

Simplicity


simple vs easy


complex:

com - "with"

plectere - "to weave, braid, entwine"


Applying FP concepts to C#


Try to avoid:

  • storing things in class members
  • modifying method arguments
  • modifying local variables
  • interleaving things unnecessarily


The less you do the above, the simpler your code gets.

Simplicity begets robustness.

Applying FP concepts to C#


Stick to good principles when they make sense:
  • single responsibility
  • don't repeat yourself
  • small, composable functions
  • separate code and data
  • separate everything!

Prefer a declarative style given the choice
Lean heavily on LINQ

Be pragmatic


Functional programming doesn't always make sense

Make a judgment call

Incorporate it slowly into your toolbox


Works best when computing values or shuffling data around

Works poorly when accessing resources:

  • web requests
  • database access

"Borders"


Pure functional programming is not practical in C#

Do what you can and glue the rest


Monad

  • some type M<T>
  • constructor for M
  • Bind function

design pattern for abstracting some functionality over types while retaining composition

wraps an object and provides a function for operating on the wrapped object

Bind must obey identity rules and be associative

Monad

Bind signature:

M<TResult> Bind<TSource, TResult>(M<TSource> m, Func<TSource, M<TResult>> f)

Bind lets you operate on a wrapped T by passing a function, while the monad takes care of whatever logic it abstracts.

Examples in C#:

  • Nullable<T>
    • optional value
  • IEnumerable<T>
    • zero or more sequential, lazy values

Explore:


Pragmatic Functional Programming

By Ross Murray

Pragmatic Functional Programming

  • 3,808