Brady Ouren

Partial Application for real

Intuitive Solutions

While working on a library recently, I came across an elegant use of partial application.

How would we model the first monday in any given month. Firstly I needed a way of passing around the concept of a month which ends up being simply fromGregorian applied to a year and month index.

The type signature being: fromGregorian :: Integer -> Int -> Int -> Day

So, a month, when partially applied, becomes a function taking an Int and returning a Day which is exactly what we want.

A common scenario for a bank holiday library is “first monday in month” and with our ability to pass in “months” to a function we define it this way:

[jan, feb, mar] = map (fromGregorian 1999) [1,2,3]

firstMondayIn month = addDays offset (month 07)
    offset = negate (weekIndex (month 02))

weekIndex day = toModifiedJulianDay day `mod` 7

The most difficult part here was figuring out how Julian time worked, but the solution ends up being super readable.

The other scenario for describing US bank holidays is the case where a holiday falls on a weekend.

january_holidays = [weekendHolidayFrom (jan 1), weekendHolidayFrom (jan 20)]

weekendHolidayFrom :: Day -> Maybe Day
weekendHolidayFrom d = case weekIndex d of
  3 -> Nothing            -- saturday
  4 -> Just (addDays 1 d) -- sunday
  _ -> Just d

From here, we have a list of Maybe Day’s so we need to filter them down to Days. There’s probably a better way of doing this, but I used mapMaybe because of the type: (a -> Maybe b) -> [a] -> [b]

mapMaybe id january_holidays

The subtle benefit

There is plenty said about the benefits of partial application or the lack thereof, but this isn’t really about that. It’s about the ease of prototyping this sort of solution. From what I can tell, the equivalent ruby solution would not have been as clean, because of the lack of first class partial application.

I’m also amused by this application because most other cases I read have seemingly contrived examples whereas this seems natural to me