the beast is becoming functional

74
The beast is becoming functional CoreHard, Minsk 2017 Ivan Čukić [email protected] http://cukic.co

Upload: corehardby

Post on 22-Jan-2018

60 views

Category:

Technology


1 download

TRANSCRIPT

Page 1: The beast is becoming functional

The beast is becoming functional

CoreHard, Minsk 2017

Ivan Čukić

[email protected]://cukic.co

Page 2: The beast is becoming functional

The Miracle of Birth Growth and Learning Fighting Each Other The Autumn Years CODE: ctwcorehard

Disclaimer

Make your code readable. Pretend the next personwho looks at your code is a psychopath and theyknow where you live.

Philip Wadler

2

Page 3: The beast is becoming functional

The Miracle of Birth Growth and Learning Fighting Each Other The Autumn Years CODE: ctwcorehard

Connections

3

Page 4: The beast is becoming functional

The Miracle of Birth Growth and Learning Fighting Each Other The Autumn Years CODE: ctwcorehard

Functional programming

Higher-order functions

Algebraic data types

Purity

Laziness

etc.

4

Page 5: The beast is becoming functional

THE MIRACLE OF BIRTH

Page 6: The beast is becoming functional

The Miracle of Birth Growth and Learning Fighting Each Other The Autumn Years CODE: ctwcorehard

The Machine that Goes ”Ping”

#include <functional>#include <algorithm>

6

Page 7: The beast is becoming functional

The Miracle of Birth Growth and Learning Fighting Each Other The Autumn Years CODE: ctwcorehard

The Machine that Goes ”Ping”

7

Page 8: The beast is becoming functional

The Miracle of Birth Growth and Learning Fighting Each Other The Autumn Years CODE: ctwcorehard

The Machine that Goes ”Ping”

7

Page 9: The beast is becoming functional

The Miracle of Birth Growth and Learning Fighting Each Other The Autumn Years CODE: ctwcorehard

The Machine that Goes ”Ping”

template <typename It, typename Predicate>

std::pair<It, It>

move_selection(It first, It last,

It destination,

Pred predicate)

{

return std::make_pair(

std::stable_partition(first, destination,

negate(predicate));

std::stable_partition(destination, last,

predicate)

);

}

8

Page 10: The beast is becoming functional

The Miracle of Birth Growth and Learning Fighting Each Other The Autumn Years CODE: ctwcorehard

The Machine that Goes ”Ping”

operator() + templates

9

Page 11: The beast is becoming functional

The Miracle of Birth Growth and Learning Fighting Each Other The Autumn Years CODE: ctwcorehard

The Machine that Goes ”Ping”

std::multiplies<float>()std::bind1st(⋯)

arg1 * arg2 boost.phoenix

10

Page 12: The beast is becoming functional

The Miracle of Birth Growth and Learning Fighting Each Other The Autumn Years CODE: ctwcorehard

The Machine that Goes ”Ping”

std::multiplies<>()std::bind(⋯)

arg1 * arg2 boost.phoenix

11

Page 13: The beast is becoming functional

The Miracle of Birth Growth and Learning Fighting Each Other The Autumn Years CODE: ctwcorehard

The Machine Stopped

Problems:

One-off functions

Problems with iterators

Problem with tuples

12

Page 14: The beast is becoming functional

GROWTH AND LEARNING

Page 15: The beast is becoming functional

The Miracle of Birth Growth and Learning Fighting Each Other The Autumn Years CODE: ctwcorehard

Lambdas

Lambdas – syntactic sugar for creating function objects:

std::stable_partition(

first, destination,

[&] (auto&& value) {

return !predicate(FWD(value));

});

// FWD - std::forward<decltype(value)>(value)

14

Page 16: The beast is becoming functional

The Miracle of Birth Growth and Learning Fighting Each Other The Autumn Years CODE: ctwcorehard

Algorithm composition

15

Page 17: The beast is becoming functional

The Miracle of Birth Growth and Learning Fighting Each Other The Autumn Years CODE: ctwcorehard

Algorithm composition

people.erase(

std::remove_if(people.begin(), people.end(),

is_not_female),

people.end());

// or std::copy_if

std::transform(people.begin(), people.end(),

std::back_inserer(names),

&person::name);

16

Page 18: The beast is becoming functional

The Miracle of Birth Growth and Learning Fighting Each Other The Autumn Years CODE: ctwcorehard

Algorithm composition

Ranges to the rescue:

people | filter(is_female)| transform(&person::name);

17

Page 19: The beast is becoming functional

The Miracle of Birth Growth and Learning Fighting Each Other The Autumn Years CODE: ctwcorehard

Algorithm composition

auto mistery_function(vector<gadget> gadgets, int offset, int count){

vector<gadget> result;int skipped = 0, took = 0;

for (const auto &gadget: gadgets) {if (is_container(gadget))

continue;

vector<gadget> children;

for (const auto &child: children(gadget)) {if (is_visible(child)) {

if (skipped < offset) {skipped++;

} else if (took <= count) {took++;children.push_back(child);

}}

}

copy(children.cbegin(), children.cend(), back_inserter(result));}

return result;}

18

Page 20: The beast is becoming functional

The Miracle of Birth Growth and Learning Fighting Each Other The Autumn Years CODE: ctwcorehard

Algorithm composition

auto mistery_function(vector<gadget> gadgets,

int offset, int count)

{

return gadgets | filtered(is_container)

| transformed(children)

| flatten()

| filtered(is_visible)

| drop(offset)

| take(count);

}

19

Page 21: The beast is becoming functional

The Miracle of Birth Growth and Learning Fighting Each Other The Autumn Years CODE: ctwcorehard

The Meaning of Tuples

template <typename It, typename Predicate>

std::pair<It, It>

move_selection(It first, It last,

It destination,

Pred predicate)

{

}

20

Page 22: The beast is becoming functional

The Miracle of Birth Growth and Learning Fighting Each Other The Autumn Years CODE: ctwcorehard

The Meaning of Tuples

auto selection = move_selection(⋯);

std::sort(selection.first, selection.second);

21

Page 23: The beast is becoming functional

The Miracle of Birth Growth and Learning Fighting Each Other The Autumn Years CODE: ctwcorehard

The Meaning of Tuples

auto [ selected_begin, selected_end ] =

move_selection(⋯);

std::sort(selected_begin, selected_end);

22

Page 24: The beast is becoming functional

FIGHTING EACH OTHER

Page 25: The beast is becoming functional

The Miracle of Birth Growth and Learning Fighting Each Other The Autumn Years CODE: ctwcorehard

Word counting

Problem:Create a program that fetches a web pageand counts the words in that page

24

Page 26: The beast is becoming functional

The Miracle of Birth Growth and Learning Fighting Each Other The Autumn Years CODE: ctwcorehard

Word counting

States:

The initial state

The counting state

The final state

25

Page 27: The beast is becoming functional

The Miracle of Birth Growth and Learning Fighting Each Other The Autumn Years CODE: ctwcorehard

Word counting

struct state_t {

bool started = false;

bool finished = false;

unsigned count = 0; not needed until startedstring url;

socket_t web_page;

};

26

Page 28: The beast is becoming functional

The Miracle of Birth Growth and Learning Fighting Each Other The Autumn Years CODE: ctwcorehard

Word counting

struct state_t {

bool started = false;

bool finished = false;

unsigned count = 0;

string url; not needed after startedsocket_t web_page;

};

26

Page 29: The beast is becoming functional

The Miracle of Birth Growth and Learning Fighting Each Other The Autumn Years CODE: ctwcorehard

Word counting

struct state_t {

bool started = false;

bool finished = false;

unsigned count = 0;

string url;

socket_t web_page; needed only while working};

26

Page 30: The beast is becoming functional

The Miracle of Birth Growth and Learning Fighting Each Other The Autumn Years CODE: ctwcorehard

Word counting

struct state_t {bool started = false;bool finished = true;unsigned count = 42;string url = ”http://isocpp.org”;socket_t web_page = ⋯;

};

27

Page 31: The beast is becoming functional

The Miracle of Birth Growth and Learning Fighting Each Other The Autumn Years CODE: ctwcorehard

Fighting each other

28

Page 32: The beast is becoming functional

The Miracle of Birth Growth and Learning Fighting Each Other The Autumn Years CODE: ctwcorehard

Sum types

A sum of types A and B is a type that contains an instance ofA or an instance of B, but not both at the same time.

A ∪ B

29

Page 33: The beast is becoming functional

The Miracle of Birth Growth and Learning Fighting Each Other The Autumn Years CODE: ctwcorehard

Sum types using inheritance

We can implement sum types through inheritance.

Create a state_t super-class, and sub-classes for each ofthe states.

30

Page 34: The beast is becoming functional

The Miracle of Birth Growth and Learning Fighting Each Other The Autumn Years CODE: ctwcorehard

Sum types using inheritance

class state_t {protected:

state_t(int type) we can not create instances: type(type) of this type directly

{}

public:const int type;virtual ~state_t() {};

};

31

Page 35: The beast is becoming functional

The Miracle of Birth Growth and Learning Fighting Each Other The Autumn Years CODE: ctwcorehard

Sum types using inheritance

class init_t: public state_t {public:

enum { id = 0 };

init_t(): state_t(id)

{}

string url;};

32

Page 36: The beast is becoming functional

The Miracle of Birth Growth and Learning Fighting Each Other The Autumn Years CODE: ctwcorehard

Sum types using inheritance

class running_t: public state_t {public:

enum { id = 1 };

init_t(): state_t(id)

{}

unsigned m_count = 0;socket_t m_web_page;

};

33

Page 37: The beast is becoming functional

The Miracle of Birth Growth and Learning Fighting Each Other The Autumn Years CODE: ctwcorehard

Sum types using inheritance

class finished_t: public state_t {public:

enum { id = 2 };

init_t(): state_t(id)

{}

const unsigned m_count = 0;};

34

Page 38: The beast is becoming functional

The Miracle of Birth Growth and Learning Fighting Each Other The Autumn Years CODE: ctwcorehard

Sum types using inheritance

35

Page 39: The beast is becoming functional

The Miracle of Birth Growth and Learning Fighting Each Other The Autumn Years CODE: ctwcorehard

Sum types using inheritance

class program_t {public:

program_t() The initial: m_state(make_unique<init_t>()) program state

{}

void counting_finished(){

assert(m_state->type == running_t::id);auto state =

static_cast<running_t*>(m_state.get());

m_state.reset(make_unique<finished_t>(state->m_count));

}

private:unique_ptr<state_t> m_state;

};

36

Page 40: The beast is becoming functional

The Miracle of Birth Growth and Learning Fighting Each Other The Autumn Years CODE: ctwcorehard

Sum types using inheritance

class program_t {public:

program_t(): m_state(make_unique<init_t>())

{}

void counting_finished(){

assert(m_state->type == running_t::id); We must have been runningauto state = in order for this function

static_cast<running_t*>(m_state.get()); to be called

m_state.reset(make_unique<finished_t>(state->m_count));

}

private:unique_ptr<state_t> m_state;

};

36

Page 41: The beast is becoming functional

The Miracle of Birth Growth and Learning Fighting Each Other The Autumn Years CODE: ctwcorehard

Sum types using inheritance

class program_t {public:

program_t(): m_state(make_unique<init_t>())

{}

void counting_finished(){

assert(m_state->type == running_t::id);auto state =

static_cast<running_t*>(m_state.get());

m_state.reset(make_unique<finished_t>(state->m_count)); Changing state

}

private:unique_ptr<state_t> m_state;

};

36

Page 42: The beast is becoming functional

The Miracle of Birth Growth and Learning Fighting Each Other The Autumn Years CODE: ctwcorehard

Sum types using inheritance

We can have no invalid states

Set of states is easily extendable (open sum types)

Automatic resource disposal for resources tied to aparticular state

Bad: A lot of boilerplate

37

Page 43: The beast is becoming functional

The Miracle of Birth Growth and Learning Fighting Each Other The Autumn Years CODE: ctwcorehard

Type-safe unions

38

Page 44: The beast is becoming functional

The Miracle of Birth Growth and Learning Fighting Each Other The Autumn Years CODE: ctwcorehard

Type-safe unions

struct init_t { string url; };

struct running_t {unsigned m_count;socket_t m_web_page;

};

struct finished_t {const unsigned m_count;

}

std::variant < init_t We can just list all, running_t the types that we want, finished_t to use for state handling> m_state;

39

Page 45: The beast is becoming functional

The Miracle of Birth Growth and Learning Fighting Each Other The Autumn Years CODE: ctwcorehard

Type-safe unions

void counting_finished()

{

auto *state = get_if<running_t>(&m_state);

assert(state != nullptr);

m_state = finished_t(state->m_count);

}

40

Page 46: The beast is becoming functional

The Miracle of Birth Growth and Learning Fighting Each Other The Autumn Years CODE: ctwcorehard

Type-safe unions

We can have no invalid states

Set of states is fixed (closed sum types)

Automatic resource disposal for resources tied to aparticular state

No boilerplate

41

Page 47: The beast is becoming functional

The Miracle of Birth Growth and Learning Fighting Each Other The Autumn Years CODE: ctwcorehard

Type-safe unions

std::visit(

[] (const auto& value) {

std::cout << value << std::endl;

}, m_state);

42

Page 48: The beast is becoming functional

The Miracle of Birth Growth and Learning Fighting Each Other The Autumn Years CODE: ctwcorehard

Type-safe unions

template <typename... Ts>

struct overloaded: Ts... { using Ts::operator()...; };

std::visit(overloaded {

[&] (const init_t& state) {

},

[&] (const running_t& state) {

},

[&] (const finished_t& state) {

}

}, m_state);

43

Page 49: The beast is becoming functional

The Miracle of Birth Growth and Learning Fighting Each Other The Autumn Years CODE: ctwcorehard

Optional values

std::optional<T> – a sum type of T and nothing

struct nothing_t {};

template <typename T>using optional = variant<nothing_t, T>;

But with a nicer API.

44

Page 50: The beast is becoming functional

The Miracle of Birth Growth and Learning Fighting Each Other The Autumn Years CODE: ctwcorehard

Optional values

When we have optional arguments

When a function can fail

...

45

Page 51: The beast is becoming functional

The Miracle of Birth Growth and Learning Fighting Each Other The Autumn Years CODE: ctwcorehard

Optional values

template <typename T, typename Variant>

optional<T> get_if(const Variant& variant)

{

T* ptr = std::get_if<T>(&variant);

if (ptr) {

return *ptr;

} else {

return optional<T>();

}

}

46

Page 52: The beast is becoming functional

The Miracle of Birth Growth and Learning Fighting Each Other The Autumn Years CODE: ctwcorehard

Error handling

The optional does not keep information about the error.

template<typename T, typename E = std::exception_ptr>

class expected {

public:

// ⋯

private:

union {

T m_value;

E m_error;

};

bool m_valid;

};

47

Page 53: The beast is becoming functional

The Miracle of Birth Growth and Learning Fighting Each Other The Autumn Years CODE: ctwcorehard

Error handling

template<typename T, typename E = std::exception_ptr>

class expected {

public:

const T& get() const

{

if (!m_valid) {

throw logic_error(”Missing a value”);

}

return m_value;

}

// ⋯

private:

// ⋯

};

48

Page 54: The beast is becoming functional

The Miracle of Birth Growth and Learning Fighting Each Other The Autumn Years CODE: ctwcorehard

Error handling

template<typename T, typename E = std::exception_ptr>

class expected {

public:

template <typename... ConsParams>

static expected success(ConsParams&& ...params)

{

expected result;

result.m_valid = true;

new (&result.m_value)

T(forward<ConsParams>(params)...);

return result;

}

// ⋯

private:

// ⋯

};

49

Page 55: The beast is becoming functional

The Miracle of Birth Growth and Learning Fighting Each Other The Autumn Years CODE: ctwcorehard

Error handling

template<typename T, typename E = std::exception_ptr>

class expected {

public:

~expected()

{

if (m_valid) {

m_value.~T();

} else {

m_error.~E();

}

}

// ⋯

private:

// ⋯

};

50

Page 56: The beast is becoming functional

The Miracle of Birth Growth and Learning Fighting Each Other The Autumn Years CODE: ctwcorehard

Error handling

template<typename T, typename E = std::exception_ptr>

class expected {

public:

expected(const expected& other)

: m_valid(other.m_valid)

{

if (m_valid) {

new (&m_value) T(other.m_value);

} else {

new (&m_error) E(other.m_error);

}

}

// ⋯

private:

// ⋯

};

51

Page 57: The beast is becoming functional

The Miracle of Birth Growth and Learning Fighting Each Other The Autumn Years CODE: ctwcorehard

Error handling

public:void swap(expected& other){

using std::swap;if (m_valid) {

if (other.m_valid) {swap(m_value, other.m_value);

} else {auto temp = std::move(other.m_error);

other.m_error.~E();new (&other.m_value) T(std::move(m_value));

m_value.~T();new (&m_error) E(std::move(temp));

std::swap(m_valid, other.m_valid);}

} else {// ⋯

52

Page 58: The beast is becoming functional

The Miracle of Birth Growth and Learning Fighting Each Other The Autumn Years CODE: ctwcorehard

Error handling

public:

void swap(expected& other)

{

using std::swap;

if (m_valid) {

// ⋯

} else {

if (other.m_valid) {

other.swap(*this);

} else {

swap(m_error, other.m_error);

}

}

}

};

53

Page 59: The beast is becoming functional

The Miracle of Birth Growth and Learning Fighting Each Other The Autumn Years CODE: ctwcorehard

Handling optional and expected values

optional<string> login = current_user();

if (!user) return error

optional<user_t> user = get_info(login.get());

if (!user) return error

optional<string> full_name =

get_full_name(user.get());

if (full_name) return error

54

Page 60: The beast is becoming functional

The Miracle of Birth Growth and Learning Fighting Each Other The Autumn Years CODE: ctwcorehard

Handling optional and expected values

Optional (and expected) values are like containers with atmost one element.

55

Page 61: The beast is becoming functional

The Miracle of Birth Growth and Learning Fighting Each Other The Autumn Years CODE: ctwcorehard

Handling optional and expected values

current_user: () -> optional<string>

get_info: string -> optional<user_t>

get_full_name: user_t -> optional<string>

current_user()

| transform(get_info)

| transform(get_full_name)

| ⋯

;

56

Page 62: The beast is becoming functional

The Miracle of Birth Growth and Learning Fighting Each Other The Autumn Years CODE: ctwcorehard

Handling optional and expected values

current_user: () -> optional<string>

get_info: string -> optional<user_t>

get_full_name: user_t -> optional<string>

current_user()

| mbind(get_info)

| mbind(get_full_name)

| ⋯

;

57

Page 63: The beast is becoming functional

THE AUTUMN YEARS

Page 64: The beast is becoming functional

The Miracle of Birth Growth and Learning Fighting Each Other The Autumn Years CODE: ctwcorehard

Handling future values

Future values are like containers that will get the valuelater.

59

Page 65: The beast is becoming functional

The Miracle of Birth Growth and Learning Fighting Each Other The Autumn Years CODE: ctwcorehard

Handling future values

current_user: () -> future<string>get_info: string -> future<user_t>get_full_name: user_t -> future<string>

current_user()| mbind(get_info)| mbind(get_full_name)| ⋯;

60

Page 66: The beast is becoming functional

The Miracle of Birth Growth and Learning Fighting Each Other The Autumn Years CODE: ctwcorehard

Handling future values

current_user: () -> future<string>get_info: string -> future<user_t>get_full_name: user_t -> future<string>

current_user().then(get_info).then(get_full_name)⋯;

61

Page 67: The beast is becoming functional

The Miracle of Birth Growth and Learning Fighting Each Other The Autumn Years CODE: ctwcorehard

Imperative on top

current_user: () -> future<string>

get_info: string -> future<user_t>

get_full_name: user_t -> future<string>

auto user = co_await current_user();

auto info = co_await get_info(user);

auto name = co_await get_full_name(info);

62

Page 68: The beast is becoming functional

The Miracle of Birth Growth and Learning Fighting Each Other The Autumn Years CODE: ctwcorehard

Imperative on top

co_await expression is equivalent to:

{

auto && tmp = <expr>;

if (!await_ready(tmp)) {

await_suspend(tmp, continuation);

}return await_resume(tmp);

}

63

Page 69: The beast is becoming functional

The Miracle of Birth Growth and Learning Fighting Each Other The Autumn Years CODE: ctwcorehard

Imperative on top

A core-language feature to implement .then

64

Page 70: The beast is becoming functional

The Miracle of Birth Growth and Learning Fighting Each Other The Autumn Years CODE: ctwcorehard

Imperative on top

A core-language feature to implement mbind

64

Page 71: The beast is becoming functional

The Miracle of Birth Growth and Learning Fighting Each Other The Autumn Years CODE: ctwcorehard

Imperative on top

current_user: () -> optional<string>

get_info: string -> optional<user_t>

get_full_name: user_t -> optional<string>

auto user = co_await current_user();

auto info = co_await get_info(user);

auto name = co_await get_full_name(info);

65

Page 72: The beast is becoming functional

The Miracle of Birth Growth and Learning Fighting Each Other The Autumn Years CODE: ctwcorehard

Summary

First, higher-order functions

Then, alternative type design safe state handling withsum types

Combination of the two

Monadic design

Finally baking the monad into the core-language

66

Page 73: The beast is becoming functional

The Miracle of Birth Growth and Learning Fighting Each Other The Autumn Years CODE: ctwcorehard

Compilation process

Write imperative co_await-based code

Converted to functional (monadic) design

Uses TMP for the type

Unwraps all into imperative code

Converted to a single-assignment internal compilerlanguage

To be finally converted to assembly

67

Page 74: The beast is becoming functional

The Miracle of Birth Growth and Learning Fighting Each Other The Autumn Years CODE: ctwcorehard

Answers? Questions! Questions? Answers!

Kudos (in chronological order):

Friends at KDESaša Malkov and Zoltan PorkolabАнтон Наумович and Сергей Платонов

MEAP – Manning Early Access Program

Functional Programming in C++cukic.co/to/fp-in-cpp

Discount code (40% off all Manning books):

ctwcorehard

68