Here is the code to get the "ideal output":
printPascal :: [[Integer]] -> IO ()
printPascal pasc =
let
process row =
let
striped = (foldr1 (\ x y -> x ++ " " ++ y) . map show) row
spaces = replicate ((n - length striped) `div` 2) ' '
in spaces ++ striped ++ "\n"
n = length . (foldr1 (\ x y -> x ++ " " ++ y) . map show) . last $ pasc
in mapM_ (putStr . process) pasc
First of all, here are some samples (the latter one does not look great, truth be told - see Edit for a better version):
GHCi> printPascal (pascal 1)
1
GHCi> printPascal (pascal 4)
1
1 1
1 2 1
1 3 3 1
GHCi> printPascal (pascal 8)
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
1 5 10 10 5 1
1 6 15 20 15 6 1
1 7 21 35 35 21 7 1
So, what is happening here:
- We take an already built triangle
pasc
. We turn the last row into a string, putting all the elements in a string, separated by spaces. That's the length of each row in our final triangle.
- We take each row and process it with
process
. It does a simple thing: it puts all the elements in a string, separated by spaces. If its length is less then n
, it adds the missing spaces (equal amount on both right and left; in fact, the spaces on the right might be dropped, as it is done). At the end we put a new line.
- We map
putStr . process
over the list and then sequence the effects. mapM
(or its more general version - traverse
) serves for such purposes. The resulting type would have been IO [()]
- we do not need a list of units, so we make it IO ()
by replacing mapM
with mapM_
(or its more general version - traverse_
).
You might want to combine pascal
and printPascal
:
buildAndPrintPascal :: Integer -> IO ()
buildAndPrintPascal = printPascal . pascal
Edit: to make the tree look a bit nicer for bigger numbers we might want to change the step (keeping it odd). Here is the edited version of the code, the only edit is the step
:
printPascal :: [[Integer]] -> IO ()
printPascal pasc =
let
process row =
let
striped = (foldr1 (\ x y -> x ++ step ++ y) . map show) row
spaces = replicate ((n - length striped) `div` 2) ' '
in spaces ++ striped ++ "\n"
n = length . (foldr1 (\ x y -> x ++ step ++ y) . map show) . last $ pasc
step =
let
times = (floor . logBase 10 . fromInteger . maximum . last $ pasc) * 2 + 1
in replicate times ' '
in mapM_ (putStr . process) pasc
Here are some samples:
GHCi> buildAndPrintPascal 4
1
1 1
1 2 1
1 3 3 1
GHCi> buildAndPrintPascal 8
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
1 5 10 10 5 1
1 6 15 20 15 6 1
1 7 21 35 35 21 7 1
GHCi> buildAndPrintPascal 10
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
1 5 10 10 5 1
1 6 15 20 15 6 1
1 7 21 35 35 21 7 1
1 8 28 56 70 56 28 8 1
1 9 36 84 126 126 84 36 9 1
I reckon them to look a bit nicer.