#!/usr/bin/ruby

#
## http://rosettacode.org/wiki/Faulhaber%27s_formula
#

func bernoulli({.is_one}) { 1/2 }
func bernoulli({.is_odd}) { 0/1 }

func bernoulli(n) {

    var a = []
    for m in ^(n+1) {
        a[m] = 1/(m + 1)
        for j in (m^..0 + 1) {
            a[j-1] = j*(a[j-1] - a[j])
        }
    }

    return a[0]
}

func faulhaber_s_formula(p) {

    var formula = gather {
        { |j|
            take "(#{binomial(p+1, j) * j.bernfrac -> as_rat})*n^#{p+1 - j}"
        } << 0..p
    }

    formula.grep! { !.contains('(0)*') }.join!(' + ')

    formula -= /\(1\)\*/g
    formula -= /\^1\b/g
    formula.gsub!(/\(([^+]*?)\)/, { _ })

    "1/#{p + 1} * (#{formula})"
}

{ |p|
    printf("%2d: %s\n", p, faulhaber_s_formula(p))
} << ^10
