Point free notation, recursion, and pattern matching

Viewed 963

So I keep hearing a lot about point free programming and I decided to do a little experiment to test my grasp of it. This involved taking a pointed function to calculate the factorial of a number and converting it to a point-free form. I managed to do it, but the point free result is a lot less readable than the pointed result.

-- pointed
fact 0 = 1
fact n = n * (fact (n-1))
-- point free
fact' = foldr1 (*) . takeWhile ((<) 0) . iterate (flip (-) 1)

Am I missing something essential to point free notation or is this as readable as certain transformations get? To me it seems that a big part of the fact function is the pattern match on zero, and indeed, pattern matching is one of the biggest reasons I love Haskell. However point free notation seems to completely disallow that, along with some other things that are extremely useful like list comprehensions.

2 Answers

For each algebraic union data type there should exist its type case discriminator function which encapsulates the pattern matching for that type. We already have

either :: (a -> c) -> (b -> c) -> Either a b -> c
maybe :: b -> (a -> b) -> Maybe a -> b

Similarly there must be such function for numbers,

num :: (Num a) => b -> (a -> b) -> a -> b
num z nz 0 = z
num z nz x = nz x

so we can write

import Control.Applicative
import Data.Function

fact :: (Num a) => a -> a
fact x = num 1 (\x-> (*) (fact (pred x)) x) x
       = num 1 ((*) =<< (fact.pred)) x

i.e.

fact   = (num 1 . ((*) =<<) . (. pred)) fact
       = fix (num 1 . ((*) =<<) . (. pred)) 
Related