# I made the fixed-point combinator using recursion for simplicity
function fix(fn)
Z = fn( (input...) -> Z(input...) ) # named after the strict Z combinator (which I'm using)
end
fac = (fac) -> (n) -> if (n < 2) 1 else n*fac(n-1) end
fib = (fib) -> (n) -> if (n < 2) n else fib(n-2)+fib(n-1) end
fix(fac)(6)
fix(fib)(5)
Now to do something interesting. I want to make a trace wrapper that will print out the function name with its arguments whenever its called. First I make a type. The name holds the function name as a string. The funcall element holds the anonymous definition. Eventually I'd like to do this with mutually recursive functions.
type Function
name
funcall
end
function trace(f)
(Yf) -> (input) -> begin
output = f.funcall(Yf)(input)
println(f.name, "(", input, ") = ", output)
output
end
end
fix( trace( Function("factorial", fac) ) )(8)
Beautiful!
fix( trace( Function("fibonacci", fib) ) )(6)
Eh...less beautiful but still cool. Obviously memoization is needed to keep fibonacci from being exponential.
function memoize(f)
inputs = []
outputs = []
(Yf) -> (input) -> begin
# test to see if input already given
match = find( (elem)->(elem == input), inputs )
if length(match) == 0
# result hasn't been found
output = f(Yf)(input)
inputs = [inputs, input]
outputs = [outputs, output]
else
# result has already been memoized
output = outputs[match[1]]
end
output
end
end
I like this version of memoization much better than my previous version. It's nowhere near as cluttered.
fix( memoize( trace( Function("fibonacci", fib) ) ) )(6)
Yeeeeessssssssss!!!! Okay the fixed-point combinator has the ability to work with multiple inputs. How about a tail recursive fibonacci function?
fib_tail = (fib) -> (n, a, b) -> if (n < 2) b else fib(n-1, b, a+b) end
fix(fib_tail)(100, 0, 1)
@time fix(fib_tail)(100, 0, 1)
# better trace wrapper for functions with multiple inputs
function trace_(f)
(Yf) -> (input...) -> begin
println(f.name, input)
f.funcall(Yf)(input...)
end
end
fix( trace_( Function("fib", fib_tail) ) )(6, 0, 1)