Start by assigning an index to each element in the triangle:
| 0 1 2 3 4 5 6
--+--------------------------
0 | 1
1 | 1 1
2 | 1 2 1
3 | 1 3 3 1
4 | 1 4 6 4 1
5 | 1 5 10 10 5 1
6 | 1 6 15 20 15 6 1
Here I've simply put the triangle on its side so that we can number them. So here I'd say that the element at (6, 4)
is 15
, whereas (4, 6)
doesn't exist. Now focus on writing a function
pascal :: Integer -> Integer -> Integer
pascal x y = ???
Such that you can generate this version of the triangle. You can start by writing
pascal x y
| x == 0 = 1
| x == y = 1
| x < y = error "Not a valid coordinate for Pascal's triangle."
| otherwise = pascal ? ? + pascal ? ?
Note that here, instead of figuring out which elements should be added together by diagonals, you can do it via rectangular coordinates. Here, you'll note that y
is which row in the triangle you're on and x
is the position of the element in that row. All you need to do is figure out what goes in place of the ?
s.
Once you get that working, I've got a one-liner for this triangle that is more efficient and can generate the entire triangle all at once while still using recursion:
import Data.List (scanl1)
pascals :: [[Integer]]
pascals = repeat 1 : map (scanl1 (+)) pascals
Don't try turning this solution in to your professor, it's not what they're looking for and it would make it pretty obvious someone gave you this solution if you've only been doing Haskell for a week. However, it really shows how powerful Haskell can be for this sort of problem. I would show how to index pascals
to get a given (n, k)
value, but doing so would also give you too many hints for solving the naive recursion.
Since there's been some confusion, the reason why I gave this solution is to draw a parallel between it and the often shown lazy implementation for the Fibonacci sequence:
fibs = 1 : 1 : zipWith (+) fibs (tail fibs)
Compared to
fib 0 = 1
fib 1 = 1
fib n = fib (n - 1) + fib (n - 2)
This definition generates an infinite list of all the Fibonacci numbers, and does so quite efficiently (from the point of view of the CPU, RAM is a different story). It encodes in its first 2 elements the base case, then a recursive expression that can calculate the rest. For the Fibonaccis, you need 2 values to start you off, but for Pascal's triangle, you only need one value, that value just happens to be an infinite list. There is an easy to see pattern going across the columns in the grid I posted above, the scanl1 (+)
function just takes advantage of this pattern and allows us to generate it very easily, but this is generating the diagonals of the triangle rather than the rows. To get the rows, you can index this list, or you can do some fancy tricks with take
, drop
, and other such functions, but that's an exercise for another day.