To write this in Haskell is really straightforward:
let y g = g (y g)
Yes. Just that easy.
The type of the function y is now:
y :: (t -> t) -> t
That is to say y is a function, that takes a function that takes a type "t" and returns a type "t" and returns a type "t".
This form of type is consistent with being a fixed point calculator for functions. (see the top of that wikipedia article linked earlier for an explanation of a fixed point of a function).
Can this be used to compute a fibonacci function from a fibonacci step? You bet!
let fs = (\n -> (\x -> if x =< 1 then 1 else (n (x -1)) + (n (x - 2))))
Now just like before, in scheme, we can use this to try to manually unroll recursion via the "n" argument which is a function to be run next.
((fs (fs (fs (fs (fs undefined))))) 5)
8
So let's run it with Y
((y fs) 5)
8
or something larger
((y fs) 10)
89
Strictly speaking, writing trace in a pure functional language is not allowed, unless you break the rules. Debug.Trace.trace lets you do this, and since I'm tracing anyway...
let tracestep label = (\f -> (\g -> (\n -> let res = (f g) n in (Debug.Trace.trace (label ++ " " ++ (show res)) res))))
Can I still compose this with "y"?
((y (tracestep "fib" fs)) 5)
fib 1
fib 1
fib 2
fib 1
fib 3
fib 1
fib 1
fib 2
fib 5
fib 1
fib 1
fib 2
fib 1
fib 3
fib 8
8
Yes!
I was going to write about memoizing this as in the Scheme example, but I'm quite tired, and my wife and I watch So You Think You Can Dance, so that's what I'm going to do instead.
No comments:
Post a Comment