/// For a function, f, define fix(f) as the "fixed point" of f: /// A value, z, such that f(z) = z. /// /// Substituting fix(f) for z, gives f(fix(f)) = fix(f), which /// we flip to fix(f) = f(fix(f)). /// /// This fixed point, z, is itself a function that takes an /// argument, x. We have to make x explicit in the definition /// in order to avoid infinite recursion when fix is called. /// /// (In a typed language like F#, fix has to be defined recursively. /// However, in an untyped system, such as the pure lambda calculus, /// fix can be defined without recursion. That version of fix is /// called the "Y" combinator.) /// /// https://en.wikipedia.org/wiki/Fixed-point_combinator let rec fix f = let z x = (f (fix f)) x z /// As an example, we create a factorial "generator", which, when /// given a function that implements factorial correctly for inputs /// up to some number, n-1, answers a slightly better function that /// implements factorial correctly for n as well. Note that this /// function is not recursive. let factorialGen (factorialWeak : int -> int) : (int -> int) = fun n -> if n = 0 then 1 else n * factorialWeak (n - 1) /// We could feed such a generated function back into the generator /// to produce an even better version that works for all numbers /// up to n + 1. Instead, applying fix to the generator itself /// returns the generator's fixed point, as though we had iterated /// the feedback infinitely. The result is a function that implements /// factorial correctly for *all* inputs n. let factorial = fix factorialGen /// Another example: Fibonacci numbers. Again, fibGen itself isn't /// recursive. It only behaves recursively once we apply fix. let fib = let fibGen fibWeak = fun n -> if n <= 1 then 1 else fibWeak (n - 1) + fibWeak (n - 2) fix fibGen [] let main argv = printfn "" for i = 0 to 10 do printfn "%A!: %A" i (factorial i) printfn "" for i = 0 to 10 do printfn "fib(%A): %A" i (fib i) 0