Pergunta

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.

Foi útil?

Solução

The canonical factorial in pointfree form is:

fact = product . enumFromTo 1

(which is equivalent to fact n = product [1..n])

I find this to be pretty readable. However, I would concur that the original version:

fact 0 = 1
fact n = n * (fact (n-1))

Matches the definition very well and is also readable.

The point (ha!) of pointfree form is to make it easy to reason about functions as the composition of other functions. However, the factorial function isn't really an excellent candidate for this kind of reasoning.

The decision is yours, obviously.

Outras dicas

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)) 
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top