Understanding FP Concepts via Refactoring

Adam Rosien @arosien
Inner Product LLC inner-product.com

27 Apr 2019

  1. Motivation
  2. Dependencies
  3. Recursive Functions
  4. Recursive Data
  5. Summary

Motivation

Dependencies

A => B

i eat dependencies for breakfast

Composition

Classes?



( ಠ ʖ̯ ಠ)

Composition

Write a helper

Monad!

What did we do?

We need our dependencies.

In OOP we can share them via scope (class). Composition is just function composition.

In FP, we want composition for everything: monadic composition for dependency sharing, function composition for logic.

Recursive Functions

Or, refactor like it’s 192x!

Recursion is known to cause headaches.

Make it the caller’s problem

ಠ‿ಠ

Curry

I don’t want a (Int => Int) => (Int => Int) function, I want a Int => Int function!

Write a helper to do that.

(⊙_◎)

Very clever.

What did we do?

Locally, recursion itself can be an extraneous detail.

Factor it out, use a helper to put it back in.

(convert explicit recursion to continuation passing)

But wait, there’s more!

That helper can now do more than just recurse!

It can cache (memoize). It can do X.

And your code doesn’t know about any of it.

Recursive Data

DO NOT PANIC

Recursion is not my data’s problem anymore!

with some helpers to fix type inference…

Problem: BoolF[BoolF[BoolF[BoolF[...

Put the recursion in helper data

No recursion in our interpreter!

What did we do

No recursion in our data.

No recursion in our interpreter(s).

Recursion Schemes encapsulate recursive traversals.

Summary

Dependency Injection

Do less in your functions: externalize dependencies.

(but not with scope, please!)

Provide them later:

via function parameters

en masse with the Reader Monad

Recursion (in functions)

Do less in your functions: receive the thing that does the recursion.

(recursion-as-a-dependency, recursion-as-a-service)

The Y-combinator is the basic technique.

You can then have this passed-in capability do more, without changing your core logic.

Recursion (in data)

Simplify your modeling primitives (algebras).

Simplify your interpreters.

Recursion Schemes glue it all together and provide flexible processing.

When you have a local problem…

make it the caller’s problem.

Then hide that problem from the caller’s caller.


These are functional programming abstractions.

They come from refactoring.

Thank you!

Adam Rosien @arosien

Inner Product LLC inner-product.com

Hire us to teach your team! ☝︎