Fixed-point combinator
en.wikipedia.org
en.wikipedia.org
1. Every function has a fixed point.
2. A fixed-point combinator will compute it.
So what is the fixed point of f(x) = x + 1?
Also why doesn't this give us mathematical superpowers? Define f(x) = x iff x is a non-trivial zero of the Riemann zeta function...
Also I find this confusing:
"Applied to a function with one variable, the Y combinator usually does not terminate"
What does it mean for a function to terminate? Is it like the limit of a series?
Well, the fixed point of f(x)=x+1 can be interpreted as infinity. So kind of yes?
> What does it mean for a function to terminate?
Lambda calculus is a formal system that describes computation. So it literally means termination like when a computer program finishes running / halts. You have text which describes your program and you apply a few rewriting rules until you can’t. If at some point you can’t apply any more rewriting rules, you’ve reached a final state, your program has terminated.
I suppose, when you apply Y combinator eg to f(x)=x+1 then you are just going to get x+1+1+… and so on as you keep applying rewriting rules.
In a generic context a fixed point combinator will only return a fixed point of a function if one exists.
2. No. (see: 1. above)
Your confusion stems from the usual domain of application to function spaces where every function has a fixed point (ie. not all function spaces, just those that are made up of functions with at least one fixed point).
From the link above:
In the classical untyped lambda calculus, every function has a fixed point.Sorry if this question is really basic, but it's honest and I find it fascinating.
It most certainly won't be a representation of a number->number function, but a general element of untyped lambda calculus nevertheless.
It is somehow similar how you take square root of a negative number on the Complex plane. You represent your negative number as a complex number (r \mapsto r + 0i), then you can take a square root of it, but that won't correspond to a representation of a real number.
right_incr(n) =
g => y => n(g)(g(y))
and using the following shorter fixed-point combinator[2], X(f) =
( a => a(a) )( x => f(x(x)) )
I get this junk: X(right_incr)
= ( a => a(a) )( x => g => y => x(x)(g)(g(y)) )
= ( x => g => y => x(x)(g)(g(y)) ) ( x => g => y => x(x)(g)(g(y)) )
X(right_incr)(g)(y)
= let f = ( x => g => y => x(x)(g)(g(y)) )
in f(f)(g)(y)
= let .. in f(f)(g)(g(y))
= let .. in f(f)(g)(g(g(y)))
= ...
Which, as you can see, only gets more complex when I try to transform it.[1] https://en.m.wikipedia.org/wiki/Church_encoding [2] https://en.m.wikipedia.org/wiki/Fixed-point_combinator#Other...
An important class of lambda terms are those for which there is no normal form. In computational terms, these are terms that would cause you to go into an infinite loop if you tried to apply the conversion rules of lambda calculus "until" you reached a normal form (i.e., a lambda term for which there are no beta redexes).
Canonical example:
>>> (lambda fn: fn(fn)) (lambda fn: fn(fn))
Traceback (most recent call last):
...
RecursionError: maximum recursion depth exceeded
For many functions, the fixed point turns out to be a variant of this
divergent ("infinite loop") expression. Assuming a definition of "+"
that preserves divergence, then "infinite_loop" is a fixed point of
f(n) = n + 1.An encoding of the fixed point operator in python is:
y = lambda Input_Fn:((lambda f: lambda n: Input_Fn(f(f))(n)) \
(lambda f: lambda n: Input_Fn(f(f))(n)))
For fun, we will play a little bit fast and loose, and combine
standard integer arithmetic with lambda calculus.Here is a functional whose fixed point is the factorial function:
>>> fac1 = lambda f: lambda n: ((n > 1) and n * f(n-1) or 1)
Example evaluation: >>> y(fac1)(4)
24
If we use the standard encoding of the integers as Church numerals,
two would be represented as: two = lambda successor: lambda zero: successor(successor(zero))
The "add_one" function becomes: add_one = lambda n: lambda successor: lambda zero: successor(n(successor)(zero))
For concreteness (and human intuition), we can define int_zero, int_successor = 0, (lambda n: n+1)
>>> add_one(two)(int_successor)(int_zero)
3
What is a fixed point of the add_one function? >>> y(add_one)(two)(int_successor)(int_zero)
Traceback (most recent call last):
...
RecursionError: maximum recursion depth exceeded >>> fac1 = lambda f: lambda n: ((n > 1) and n * f(n-1) or 1)
If you happened to have a function "my_fac" that calculates the factorial function, and you applied "fac1" above to that function, you would get a new implementation of the factorial function, that calls your my_fac function internally. In other words, "my_fac" is a fixed point of fac1: >>> fac1(my_fac)
is the same function as my_fac.And it's not all functions, just computable ones. But if there's algorithm to compute non-trivial zeroes of the zeta function, it would just never terminate if there aren't any.
It's quite simple when thought of that way. "Fixed point" can seem like a high falutin' term of art, and that's because it is -- we love our terms of art, but we also need to be able to explain them.
`fix` then is a function which takes a function value as an argument and which returns a new function value which is a function that calls the argument to `fix` with that same argument as its first argument. Reading that I realize it's hard to express this in pure natural language -- one has to introduce symbols for naming the various functions.
In the lambda calculus, functions are nameless. Recursion is when an expression refers to itself by name. The Y combinator gives you recursion despite the contradiction in my last two sentences.
> So what is the fixed point of f(x) = x + 1?
We don't have names, so what is the fixed point of (λx. x + 1)? Introduce a new variable into the expression's body to act as the expression's name, and also include it as the first parameter:
(λf x. x + 1)
(Your function did not refer to itself which is why there's no f in the body of the above expression).Now let's take the ingredients and put them together. I'm including an 'input' so that we can converge on an output:
Y = (λg. (λh. g (h h)) (λh. g (h h)))
fixf = (λf x. x + 1)
input = 3
Y fixf input = (λg. (λh. g (h h)) (λh. g (h h))) (λf x. x + 1) 3
Now we just apply those lambdas to their terms and see what we end up with: (λg. (λh. g (h h)) (λh. g (h h))) (λf x. x + 1) 3
^ | g |
(λh. (λf x. x + 1) (h h)) (λh. (λf x. x + 1) (h h)) 3
^ | h |
(λf x. x + 1) ((λh. (λf x. x + 1) (h h)) (λh. (λf x. x + 1) (h h))) 3
^ | f |
(λx. x + 1) 3
^ |x|
4so for f(x)=1+x it is 1+ (1+ (1+ (1+ ... , an infinite sum.
This is correct in the sense that 1 + infinity = infinity, but in practice this could result in an infinite loop or stack overflow.
For f(x)=x+1 it's the reverse ...) +1) +1) +1 which behaves similarly.
It's for when you want to recurse (a function calling its own name) in an environment where you don't have names (the lambda calculus).
example shows that it's y(g)->g(y(g)), not the opposite...
> The key to understanding the fixpoint theorem, for me anyway, was realizing that when it says FG=G, it does not mean that for every F there is a G such that by calling F with parameter G one can get back G. I mention this in the blog post, above. The equality operator in FG=G is the equivalence relation induced by the calculus rewriting relation: that is, it's the symmetric reflexive transitive closure of the rewriting step relation. When you look at the proof of the theorem, it actually works by constructing an expression G such that evaluating G produces, as an intermediate result, FG. There is no need for F to even be a function, and if F is a function it doesn't matter what, if anything, F would actually do when called, because the proof of the theorem doesn't involve calling F.
I think the name "fixpoint combinator" is kindof bad, it it was called e.g. the "recursion combinator" I think people would find it more intuitive.
[0] https://fexpr.blogspot.com/2013/07/bypassing-no-go-theorems....
Given a function f, we say that an element c in the domain of f is a fixed point for f if it satisfies that f(c) = c. In a different nomenclature, if you consider f a "transformation", then c satisfies that it "remains fixed through the transformation".
The fixed-point combinator is called so, because it "produces fixed-points for a function". That is, given a function f, then FPC(f) is a fixed-point for f. So, if we call c = FPC(f), then f(c) = c. Or, more classically f(FPC(f)) = FPC(f) or f(Y(f)) = Y(f).
---
Note that when talking about fixed points in general, the domain of the f function is whatever -but usually you may have studied it with numbers-. But when talking about the fixed-point combinator the domain is functions themselves.
Y(g) = g(Y(g))
which by the definition of the equals sign (A=B and B=A say the same thing), is the same as: g(Y(g)) = Y(g)
— so Y(g) is a fixed point of g. What is the confusion?