Pascal's triangle is an arithmetic and geometric figure often associated with the name of Blaise Pascal, but also studied centuries earlier in India, Persia, China and elsewhere.

Its first few rows look like this: 

    1
   1 1
  1 2 1
 1 3 3 1 

where each element of each row is either 1 or the sum of the two elements right above it.

For example, the next row of the triangle would be:

   1   (since the first element of each row doesn't have two elements above it)
   4   (1 + 3)
   6   (3 + 3)
   4   (3 + 1)
   1   (since the last element of each row doesn't have two elements above it) 
So the triangle now looks like this: 

    1
   1 1
  1 2 1
 1 3 3 1
1 4 6 4 1 

Each row    n    (starting with row   0   at the top) shows the coefficients of the binomial expansion of    (x + y)n. 



Task

Write a function that prints out the first    n    rows of the triangle   (with    f(1)    yielding the row consisting of only the element 1).

This can be done either by summing elements from the previous rows or using a binary coefficient or combination function.

Behavior for    n ≤ 0    does not need to be uniform, but should be noted.



See also

 Evaluate binomial coefficients


-------------------- PASCAL'S TRIANGLE -------------------
 
-- pascal :: Generator [[Int]]
on pascal()
    script nextRow
        on |λ|(row)
            zipWith(my plus, {0} & row, row & {0})
        end |λ|
    end script
    iterate(nextRow, {1})
end pascal
 
 
--------------------------- TEST -------------------------
on run
    showPascal(take(7, pascal()))
end run
 
 
------------------------ FORMATTING ----------------------
 
-- showPascal :: [[Int]] -> String
on showPascal(xs)
    set w to length of intercalate("   ", item -1 of xs)
    script align
        on |λ|(x)
            |center|(w, space, intercalate("   ", x))
        end |λ|
    end script
    unlines(map(align, xs))
end showPascal
 
 
------------------------- GENERIC ------------------------
 
-- center :: Int -> Char -> String -> String
on |center|(n, cFiller, strText)
    set lngFill to n - (length of strText)
    if lngFill > 0 then
        set strPad to replicate(lngFill div 2, cFiller) as text
        set strCenter to strPad & strText & strPad
        if lngFill mod 2 > 0 then
            cFiller & strCenter
        else
            strCenter
        end if
    else
        strText
    end if
end |center|
 
 
-- intercalate :: String -> [String] -> String
on intercalate(sep, xs)
    set {dlm, my text item delimiters} to ¬
        {my text item delimiters, sep}
    set s to xs as text
    set my text item delimiters to dlm
    return s
end intercalate
 
 
-- iterate :: (a -> a) -> a -> Generator [a]
on iterate(f, x)
    script
        property v : missing value
        property g : mReturn(f)'s |λ|
        on |λ|()
            if missing value is v then
                set v to x
            else
                set v to g(v)
            end if
            return v
        end |λ|
    end script
end iterate
 
 
-- length :: [a] -> Int
on |length|(xs)
    set c to class of xs
    if list is c or string is c then
        length of xs
    else
        2 ^ 30 -- (simple proxy for non-finite)
    end if
end |length|
 
 
-- map :: (a -> b) -> [a] -> [b]
on map(f, xs)
    tell mReturn(f)
        set lng to length of xs
        set lst to {}
        repeat with i from 1 to lng
            set end of lst to |λ|(item i of xs, i, xs)
        end repeat
        return lst
    end tell
end map
 
 
-- min :: Ord a => a -> a -> a
on min(x, y)
    if y < x then
        y
    else
        x
    end if
end min
 
 
-- mReturn :: First-class m => (a -> b) -> m (a -> b)
on mReturn(f)
    -- 2nd class handler function lifted into 1st class script wrapper. 
    if script is class of f then
        f
    else
        script
            property |λ| : f
        end script
    end if
end mReturn
 
 
 
-- plus :: Num -> Num -> Num
on plus(a, b)
    a + b
end plus
 
 
-- Egyptian multiplication - progressively doubling a list, appending
-- stages of doubling to an accumulator where needed for binary 
-- assembly of a target length
-- replicate :: Int -> a -> [a]
on replicate(n, a)
    set out to {}
    if n < 1 then return out
    set dbl to {a}
 
    repeat while (n > 1)
        if (n mod 2) > 0 then set out to out & dbl
        set n to (n div 2)
        set dbl to (dbl & dbl)
    end repeat
    return out & dbl
end replicate
 
 
-- take :: Int -> [a] -> [a]
-- take :: Int -> String -> String
on take(n, xs)
    set c to class of xs
    if list is c then
        if 0 < n then
            items 1 thru min(n, length of xs) of xs
        else
            {}
        end if
    else if string is c then
        if 0 < n then
            text 1 thru min(n, length of xs) of xs
        else
            ""
        end if
    else if script is c then
        set ys to {}
        repeat with i from 1 to n
            set end of ys to xs's |λ|()
        end repeat
        return ys
    else
        missing value
    end if
end take
 
 
-- unlines :: [String] -> String
on unlines(xs)
    set {dlm, my text item delimiters} to ¬
        {my text item delimiters, linefeed}
    set str to xs as text
    set my text item delimiters to dlm
    str
end unlines
 
 
-- unwords :: [String] -> String
on unwords(xs)
    set {dlm, my text item delimiters} to ¬
        {my text item delimiters, space}
    set s to xs as text
    set my text item delimiters to dlm
    return s
end unwords
 
 
-- zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
on zipWith(f, xs, ys)
    set lng to min(|length|(xs), |length|(ys))
    if 1 > lng then return {}
    set xs_ to take(lng, xs) -- Allow for non-finite
    set ys_ to take(lng, ys) -- generators like cycle etc
    set lst to {}
    tell mReturn(f)
        repeat with i from 1 to lng
            set end of lst to |λ|(item i of xs_, item i of ys_)
        end repeat
        return lst
    end tell
end zipWith