How to avoid unnecessary computation when composing pure functions in a functional language?

253 views Asked by At

I have two functions that are a composition of pure functions. The first function takes a parcel, builds a house on it, and take a picture to advertise it in a magazine:

let buildAndAdvertiseHouse parcel = 
    parcel
    |> inspect
    |> buildWalls
    |> buildRoof
    |> takePhoto
    |> advertise

The second function takes also a parcel, builds a house on it, and adds a finishing touch to it:

let buildAndCompleteHouse parcel = 
    parcel
    |> inspect
    |> buildWalls
    |> buildRoof
    |> paintWalls
    |> addFurniture

It's clear that the two functions are also pure, since they are a composition of pure functions. Now I have a parcel, let say niceParcel and I want to apply both functions to it. However, I want to avoid that the first three sub-functions are calculated twice since they take a big time to compute and they are shared among the two functions.

How do I refactor my code, so these unnecessary calculations are avoided, while keeping these nice pure functions which have a clear meaning?

1

There are 1 answers

0
Tomas Petricek On

As others mentioned in the comments, I think the best approach is to turn the common part into a build function. Even if you do not intend to use the function for other purposes, this is a clean way of structuring functional code.

In F#, you can define a type that represents a partially built house, but does not expose its internals. This means that the callers of your library can use build to build a partially constructed house, but then the only thing they can do with it is to use the two functions you provided:

module Houses = 
  type House = private HouseData of <whatever>
  let build parcel = (...)

  let buildAndAdvertiseHouse house = 
    house
    |> takePhoto
    |> advertise

  let buildAndCompleteHouse house = 
    house
    |> paintWalls
    |> addFurniture

You can hide the fact that one needs to build a house before you can advertise & complete it in various ways. For example, if you typically do both operations at once, then you can define a function that calls all three functions - and the user of your library can either just use this or learn a bit more about house building and use the three functions if they need a finer control.

Another approach would be to just wrap the functionality in a simple type. F# mixed functional and object-oriented style, so there is nothing really wrong with having a type that runs the common part once and keeps some state.

type House(parcel) = 
  let house = 
    parcel
    |> inspect
    |> buildWalls
    |> buildRoof

  member x.BuildAndAdvertiseHouse()
    house
    |> takePhoto
    |> advertise

  member x.BuildAndCompleteHouse() = 
    house
    |> paintWalls
    |> addFurniture

This is fine in F#, but I think I would prefer the functional approach with a build function.