defmodule Pascal do @moduledoc """ Provides a set of functions that calculate Pascal's triangles """ @typedoc """ Line of Pascal's triangle """ @type line :: nonempty_list(pos_integer) @typedoc """ Pascal's triangle """ @type triangle :: nonempty_list(line) @doc """ Generate Pascal's `t:triangle/0` of given `height`. Returns `t:triangle/0`. ## Examples iex> Pascal.triangle(1) [[1]] iex> Pascal.triangle(2) [[1], [1, 1]] iex> Pascal.triangle(3) [[1], [1, 1], [1, 2, 1]] """ @spec triangle(pos_integer) :: triangle def triangle(height) do Enum.reverse triangle(height, [[1]]) end @doc """ Generate next `t:line/0` of Pascal's `t:triangle/0` for given previous `t:line/0`. Returns `t:line/0`. ## Examples iex> Pascal.next_triangle_line([1]) [1, 1] iex> Pascal.next_triangle_line([1, 1]) [1, 2, 1] iex> Pascal.next_triangle_line([1, 2, 1]) [1, 3, 3, 1] """ @spec next_triangle_line(line) :: line def next_triangle_line(line) do Enum.zip([0 | line], line ++ [0]) |> Enum.map(fn {a, b} -> a + b end) end @spec triangle(pos_integer, triangle) :: triangle defp triangle(1, triangle), do: triangle defp triangle(n, [line | _rest] = triangle) do next_line = next_triangle_line(line) triangle(n - 1, [next_line | triangle]) end end