Introduction to FP

(a C++ perspective).

Let's replace FP with just two restrictions:

Avoid throwing exceptions.

Avoid mutations.

How do we phase out or limit exceptions, global state, and loops?

A convincing demonstration of correctness being impossible as long as the mechanism is regarded as a black box, our only hope lies in not regarding the mechanism as a black box.

Why would we do this?

The good compiler  is a actually a proof assistant; so you can leverage types as propositions.

... Proof Assistant? ...

Types ≃ Propositions ≃ Objects

Terms ≃ Proofs ≃ Morphisms

Curry-Howard(-Lambek) Correspondance.

//In other words:
struct True; // not true: Boolean

We can prove logical statements by constructing elements of types

https://github.com/DanielKrawisz/Truth

Types ≃ Propositions

If you can define the method, you found the proof...

template <typename A, typename B> 
struct And { 
  A fst; 
  B snd; 
};

template <typename A, typename B> 
union Or { 
  A fst; 
  B snd; 
};

template <typename A, typename B>
B Implies(in: A);

Types ≃ Propositions

Updated for C++ 17

template<typename A, typename B>
using And = std::tuple<A, B>;

template<typename A, typename B>
using Or = std::variant<A, B>;

template<typename A, typename B>
using Implies = std::function<B(A)>;

What are we looking to write more of:

  • Total Functions
  • Referential Transparency
  • Proovable Termination

Why: Determinism

Total Functions

Avoid exceptions

int decode(std::string& s);

tl::expected<int, internal_error> 
decode(std::string& s);

Total Functions

Restrict input values

void open(std::string& filename, std::string& mode);

tl::expected<fstream, io_exception> 
open(std::string& filename, mode_enum mode);

Referential Transparency

Avoid mutation

int x = 5;
x = 3;
const int y = 5;
y = 3; // Exception

if (x = 1) // Oops

std::fstream fs;
fs.open("w")
fs.open("y") // Oops

Referential Transparency

Decouple evaluation

IO<Tiemstamp> systemTime;

systemTime()
doSomething()
sleep(1)
systemTime()
doSomethingElse()

Termination

Avoid recursion

int use(int a) { return use(a); };

int sum(int... nums) = { return (... + nums); };

Termination

Avoid loops

int use(int a) { while (true) { ... }; return a; };

mlib::lazylist<int> fib = mlib::lazylist::single<int>(0)
  .scanLeft(1)([] (int a, int b) { return a + b; });

This subset of your code composes!

Category Theory is the study of composition.

The code your write this ways obeys the laws of category theory.

Made with Slides.com