Pascal Line in Haskell

Andrew J Bromage ajb@spamcop.net
Fri, 22 Aug 2003 16:00:45 +1000


G'day all.

On Fri, Aug 22, 2003 at 09:40:12AM +1000, Job L. Napitupulu wrote:

> Can anyone help me how to make a function which takes an integer n > 0 and
> returns the list of integers in Line of Pascal's Triangle. For examples,
> 
> pascalLine 4 -> [1,4,6,4,1]
> pascalLine 7 -> [1,7,21,35,35,21,7,1]

This should do the trick.

Cheers,
Andrew Bromage

--------8<---CUT HERE---8<--------

type InfTable a = [(Integer, BinTree a)]
data BinTree a = Leaf a | Node Integer (BinTree a) (BinTree a)

swing :: Integer -> Integer
swing n = rec n (\_ _ r -> r)
  where
     rec :: Integer -> (Integer -> Integer -> Integer -> Integer) -> Integer
     rec n k
       | n < 2
         = k 1 1 1
       | otherwise
         = rec (n `div` 2) (\nn ff r -> swing' n nn ff
                     (\nn' ff' -> k nn' ff' $! (r*r*ff')))

     swing' :: Integer -> Integer -> Integer ->
             (Integer -> Integer -> Integer) -> Integer
     swing' n nn ff k
       | nn `mod` 2 == 1 = swing_odd k nn ff
       | otherwise       = swing_even k nn ff
         where
             swing_odd k nn ff
               | nn <= n   = swing_even k (nn+1) $! (ff*nn)
               | otherwise = k nn ff

             swing_even k nn ff
               | nn <= n   = swing_odd k (nn+1) $! (ff*4 `div` nn)
               | otherwise = k nn ff

recProd :: Integer -> Integer -> Integer
recProd b n
  | n < 5
    = case n of
         0 -> 1
         1 -> b
         2 -> b*(b+1)
         3 -> b*(b+1)*(b+2)
         4 -> (b*(b+1))*((b+2)*(b+3))
  | otherwise
    = let n2 = n `div` 2
      in recProd b n2 * recProd (b+n2) (n-n2)

pascalLine :: Integer -> [Integer]
pascalLine n
  | n >= 0 = searchTable n table
  where
     table :: InfTable [Integer]
     table = buildInfTable 1 5

     buildInfTable n i
        = (nextn, buildInfTable' n i) : buildInfTable nextn (i+1)
         where
             nextn = n + 2^i

             buildInfTable' base 0
                 = Leaf [ c base k | k <- [0..base] ]
                 where
                     c m n
                        | m < 0          = 0
                        | n < 0 || n > m = 0
                        | n > m `div` 2  = c' n (m-n)
                        | otherwise      = c' (m-n) n
                     c' i j = recProd (i+1) j `div` swing j
             buildInfTable' base i
                 = Node (base + midSize)
                        (buildInfTable' base (i-1))
                        (buildInfTable' (base + midSize) (i-1))
                 where
                     midSize = 2 ^ (i-1)

     searchTable x ((x',tree):ms)
         | x < x'    = searchTree x tree
         | otherwise = searchTable x ms

     searchTree x (Leaf y) = y
     searchTree x (Node mid l r)
         | x < mid   = searchTree x l
         | otherwise = searchTree x r