News for hackers. Stuff that matters.
Re:Fixed-Point Combinator by gregfjohnson on Saturday February 24, 2024 @12:21AM (#39489325)
Here is a way to look at this in concrete terms, using python.

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
Re:Fixed-Point Combinator by gregfjohnson on Saturday February 24, 2024 @02:17AM (#39489790)
One additional comment, regarding the "fac1" functional above:

  >>> 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.