문제

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.

도움이 되었습니까?

해결책

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.

다른 팁

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)) 
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top