OO Design Patterns to FP Functions

Tuesday, November 15, 2016

Design patterns are a way to describe how abstractions are passed around in code

In an object oriented language the abstractions are Interfaces, Abstract classes, Virtual Methods, etc..

For instance, given some concrete data, a Factory pattern returns an abstraction. concrete -> abstract.

public class DealFactory
    public IDeal CreateDeal(DayOfTheWeek dotw)
        switch (dotw)
            case DayOfTheWeek.Monday: return new MondayDeal();
            case DayOfTheWeek.Tuesday: return new TuesdayDeal();
            default: return new NoDeal();

This trivial factory pattern accepts a concrete Enum and returns some instance of a class implementing IDeal.

In functional languages the abstractions are functions. So taking our concept of concrete -> abstract for a factory pattern means that we would need some function that accepts a concrete value and returns a function.

A Haskell implementation could look something like this.

factory Monday = mondayDeal
factory Tuesday = tuesdayDeal
factory _ = noDeal

And F# would look very similar

let factory = function
    | Monday -> mondayDeal
    | Tuesday -> tuesdayDeal
    | _ -> noDeal

This is a way of defining a factory function that will respond to specific days and return functions depending upon the day. In the OO code, each branch had to return an instance of the same interface. In the FP code, each branch must return a function that has the same type (or signature). Or said another way, mondayDeal, tuesdayDeal, and noDeal would all have to be functions with the same signature.

Strategy Pattern

In a strategy pattern our code accepts the abstraction to do some work to return a concrete value so we have something like abstract -> concrete. It is basically the opposite of a Factory pattern and why I like explaining this by comparing the two.

public double CalculatePrice(double amount, IDeal deal)
    return deal.apply(amount);

So what would that look like in a functional sense?

let calculatePrice amount deal =
    deal amount

It's so simple there's almost no reason for defining it as a function. In fact the way we've written that function would actually compile to be so generic as to have nothing to do with Deals or amounts. Here's what that code would look like if we explicitly defined the signature in the way C# does.

public U CalculatePrice<T,U>(T amount, Func<T, U> deal)
    return deal(amount);

By assuming generic code and looking at the types we've not only solved the calculatePrice problem but also have a helper method that will apply any value to a function that accepts a value of its type.

If you've built up a large repertoire of OO design patterns over your career you should be able to use those immediately in functional code by thinking about where the abstraction is within the pattern and substituting a function for the abstraction. Often times (as in our Strategy pattern example) the resulting function will be polymorphic allowing code reuse on a level you may not have considered.