require 'test/unit'
# Author: Reginald Braithwaite
# http://weblog.raganwald.com/
class ExempliGratia < Test::Unit::TestCase
CURRY = lambda { |f, a| lambda { |*b| f.call(a, *b) } }
def test_recursive_curry
maker = lambda { |func_with_me|
CURRY.call(func_with_me, func_with_me)
}
fact = maker.call(lambda { |me, n| n.zero? && 1 or n * me.call(me, n-1) })
assert_equal(120, fact.call(5))
end
def test_refactor_fact_to_isolate_desired_form
maker = lambda { |func_with_me|
CURRY.call(func_with_me, func_with_me)
}
un_fact_ored = lambda { |me, n| n.zero? && 1 or n * me.call(me, n-1) }
assert_equal(120, maker.call(un_fact_ored).call(5))
re_fact_ored_1 = lambda { |me, n| n.zero? && 1 or n * CURRY.call(me, me).call(n-1) }
assert_equal(120, maker.call(re_fact_ored_1).call(5))
re_fact_ored_2 = lambda { |me, n| (lambda { |better_me| n.zero? && 1 or n * better_me.call(n-1) }).call(CURRY.call(me, me)) }
assert_equal(120, maker.call(re_fact_ored_2).call(5))
re_fact_ored_3 = lambda { |me, outer_n|
(lambda { |better_me|
(lambda { |inner_n| inner_n.zero? && 1 or inner_n * better_me.call(inner_n-1) }).call(outer_n) }).call(CURRY.call(me, me)) }
assert_equal(120, maker.call(re_fact_ored_3).call(5))
re_fact_ored_4 = lambda { |me, outer_n|
(lambda { |better_me|
(lambda { |inner_n| inner_n.zero? && 1 or inner_n * better_me.call(inner_n-1) }) }).call(CURRY.call(me, me)).call(outer_n) }
assert_equal(120, maker.call(re_fact_ored_4).call(5))
end
def test_refactor_maker_to_parameterize_desired_form
maker_1 = lambda { |func_with_me|
CURRY.call(func_with_me, func_with_me)
}
re_fact_ored_4 = lambda { |me, outer_n|
(lambda { |better_me|
(lambda { |inner_n| inner_n.zero? && 1 or inner_n * better_me.call(inner_n-1) }) }).call(CURRY.call(me, me)).call(outer_n) }
assert_equal(120, maker_1.call(re_fact_ored_4).call(5))
re_fact_ored_5 = CURRY.call(lambda { |func, me, outer_n|
func.call(CURRY.call(me, me)).call(outer_n) }, (lambda { |better_me|
(lambda { |inner_n| inner_n.zero? && 1 or inner_n * better_me.call(inner_n-1) }) }))
assert_equal(120, maker_1.call(re_fact_ored_5).call(5))
expanded = (lambda { |func_with_me|
CURRY.call(func_with_me, func_with_me)
}.call(CURRY.call(lambda { |func, me, outer_n|
func.call(CURRY.call(me, me)).call(outer_n) }, (lambda { |better_me|
(lambda { |inner_n| inner_n.zero? && 1 or inner_n * better_me.call(inner_n-1) }) }))))
assert_equal(120, expanded.call(5))
promoted = (lambda { |outer_func|
(lambda { |func_with_me|
CURRY.call(func_with_me, func_with_me)
}.call(CURRY.call(lambda { |func, me, outer_n|
func.call(CURRY.call(me, me)).call(outer_n) }, outer_func)))
}).call((lambda { |better_me|
(lambda { |inner_n| inner_n.zero? && 1 or inner_n * better_me.call(inner_n-1) }) }))
assert_equal(120, promoted.call(5))
#therefore
maker = (lambda { |outer_func|
(lambda { |func_with_me|
CURRY.call(func_with_me, func_with_me)
}.call(CURRY.call(lambda { |func, me, outer_n|
func.call(CURRY.call(me, me)).call(outer_n) }, outer_func)))
})
assert_equal(120, maker.call((lambda { |better_me|
(lambda { |inner_n| inner_n.zero? && 1 or inner_n * better_me.call(inner_n-1) }) })).call(5))
extracted_factorial = maker.call((lambda { |better_me|
(lambda { |inner_n| inner_n.zero? && 1 or inner_n * better_me.call(inner_n-1) }) }))
assert_equal(120, extracted_factorial.call(5))
renamed_factorial = maker.call((lambda { |f|
(lambda { |n| n.zero? && 1 or n * f.call(n-1) }) }))
assert_equal(120, renamed_factorial.call(5))
end
def test_clean_up_loose_ends
maker = lambda { |f|
lambda { |func_with_me| CURRY.call(func_with_me, func_with_me) }.call(
CURRY.call(lambda { |inner_func, me, *args|
inner_func.call(CURRY.call(me, me)).call(*args) }, f)) }
factorial = maker.call(
lambda { |f| lambda { |n| n.zero? && 1 or n * f.call(n-1) } }
)
assert_equal(120, factorial.call(5))
iterative_factorial = maker.call(
lambda { |f| lambda { |n, acc| n.zero? && acc or f.call(n - 1, n * acc) } }
)
tail_factorial = lambda { |n| iterative_factorial.call(n, 1) }
assert_equal(120, tail_factorial.call(5))
end
end

This work is licensed under a Creative Commons Public Domain License.