1 of 39

Functional Programming in Go

Aaron Schlesinger

Microsoft Azure

2 of 39

3 of 39

A Bit More About Me

Gopher @ Microsoft (formerly Deis)

Co-lead, Kubernetes SIG-Service-Catalog

Former Scala purist

Current FP student, F# & Haskell Tinkerer

I like to teach

4 of 39

FP & Go: Is This Even A Good Idea?

I think so!

Go won’t be the next Haskell any time soon

But these FP concepts are still powerful when applied appropriately

5 of 39

6 of 39

Today Is About...

Adding tools to your toolbox

A new perspective

Applying new (useful) abstractions to your code

7 of 39

8 of 39

...a style of building the structure and elements of computer programs—that treats computation as the evaluation of mathematical functions and avoids changing-state and mutable data

9 of 39

10 of 39

Functions!

11 of 39

Let’s do some functional programming!

12 of 39

Fancy Term #1: Higher Order Functions

funcs that take and/or return funcs

13 of 39

Ever Set a Global Var?

var DB *sql.DB

func myHandler(w http.ResponseWriter, r *http.Request) {

res, err := DB.Exec(...)

}

14 of 39

Easy, Until...

Testing, swapping implementations, insidious concurrency issues

The function isn’t pure; harder to work with

15 of 39

Pure Functions

Only operate on the parameters; no side effects

Predictable, easy to reason about

But, you have to do real things!

16 of 39

Let’s Rewrite! Starting With A Refresher…

// In case you forgot, this type is from net/http.

// Looks the same as the function signature of myHandler!

type HandlerFunc func(http.ResponseWriter, *http.Request)

17 of 39

Let’s Rewrite, For Real This Time!

func myHandler(db *sql.DB) http.HandlerFunc {

return func(w http.ResponseWriter, r *http.Request) {

res, err := db.Exec(...)

// …

}

}

18 of 39

Taking Higher-Order Functions On Tour

19 of 39

Transforming a Slice

ints := getIntSlice()

results := make([]int, len(ints))

for i, elt := range ints {

results[i] = doSomething(elt)

}

20 of 39

Fancy Term #2: Functors

Or, abstracting for loops

21 of 39

Transforming a Slice, The FP Way

ints := getIntSlice()

results := magical(ints).Map(doSomething)

22 of 39

magical() makes a Functor

… and a Functor is a:

  • Go struct that contains the data (i.e. a slice)
  • Map function that operates on the container

Map(fn func(int) int) IntSliceFunctor

23 of 39

Basic Usage

24 of 39

Intent, Not Implementation

We told Map what we wanted to do

Not how to do it

Same principle as SQL

25 of 39

What If We Have 1,000,000 Ints?

26 of 39

<-chan int

27 of 39

28 of 39

if ret == nil

29 of 39

Optional

A “container” that either has an element, or does not

Still has Map, also has an “escape hatch”

Map(fn func(int) int) OptionalIntFunctor

Int() int // escape hatch

30 of 39

Dealing With Uncertainty

31 of 39

if err != nil

32 of 39

Introducing Either

One value or the other

By convention, left = success, right = failure

Either<Left, Right>

33 of 39

Either

“Projects” to Optionals for left & right sides

Left() bool

Right() bool

ToLeft() Optional<Left>

ToRight() Optional<Right>

34 of 39

Either Way, You Have To Check The Result

35 of 39

We Built Foundations Today

36 of 39

… On Which We Can Build Skyscrapers

Function Composition

Type-classes

Function Currying, Partial Application

Monoids

Monads

Other funky names!

37 of 39

Let’s Have a Dialogue

38 of 39

Thank You!

39 of 39

Bonus Round! Equality Checks With Type Classes

Very similar to interfaces, just a new way to think about them. Neither of these compile:

“1” == 1

[]int{1, 2, 3} == []int{1, 2, 3}

https://github.com/go-functional/core/blob/master/examples/typeclass/eq/main.go