On Saturday, October 21, 2017 at 7:15:35 PM UTC-4,
josep...@gmail.com wrote:
> A fixed point combinator is a function that can be used to determines the fixed points in the domain and co-domain of another function. The form of the fixed-point combinator in lambda calculus is called the Y-combinator, and was originally developed by logician Haskell Curry in the 1950s (I think, it may have been earlier).
>
> A fixed point is a domain value which, when the function is applied to it, maps to the same value in the co-domain. Thus, is we apply fixed-point combinator Y to function f, then for all x, (Y f x) -> x.
Gaah, what was I thinking when I wrote that? Sorry, let me fix this. If anyone spots any further mistakes - and there almost certainly will be some - please speak up about them.
A fixed point combinator is a function that can be used to determines *a* fixed point in the domain and co-domain of another function. One of the better known fixed-point combinators in untyped lambda calculus (of which there are several known) is the Y-combinator. If we apply the Y-combinator to a function f, then it returns a value x such that x is a fixed point of f.
So,
(Y f) -> x
(f x) -> x
Y itself is defined in λ-calculus as
Y = λf.(λx.f (x x))(λx.f (x x))
I don't know if I could properly explain this, but in it would become (using the Rosetta Code example
http://rosettacode.org/wiki/Y_combinator):
(defun Y (f)
((lambda (x) (funcall x x))
(lambda (y)
(funcall f (lambda (&rest args)
(apply (funcall y y) args))))))
For comparison, using some other languages you seem interested in Scheme
,
(define Y
(lambda (h)
((lambda (x) (x x))
(lambda (g)
(h (lambda args (apply (g g) args)))))))
Forth,
\ Address of an xt.
variable 'xt
\ Make room for an xt.
: xt, ( -- ) here 'xt ! 1 cells allot ;
\ Store xt.
: !xt ( xt -- ) 'xt @ ! ;
\ Compile fetching the xt.
: @xt, ( -- ) 'xt @ postpone literal postpone @ ;
\ Compile the Y combinator.
: y, ( xt1 -- xt2 ) >r :noname @xt, r> compile, postpone ; ;
\ Make a new instance of the Y combinator.
: y ( xt1 -- xt2 ) xt, y, dup !xt ;
And if you are ready to say goodbye to what remains of your sanity by this point, there is an extended derivation in tcl at
http://wiki.tcl.tk/4833.
Note that the lambda expansion of Y is not guaranteed to terminate for all f; in fact, it generally doesn't terminate for functions of arity 1 (that is, functions which take only one argument). Applying it to functions in two or more variables often does terminate, however, which is where Y becomes useful.
Part of the result of this is that if a calculus or programming language permits higher-order functions, but doesn't explicitly permit recursion (as is the case for untyped lambda calculus), then for functions for which it does terminate, applying a function f to the value of applying Y to f:
(f (Y f))
can be used to define an effective recursion of f - the application itself can be treated as a function f' of the same arity as f, which applies f repeatedly until it can not be expanded further. So, if you want a function that adds x and y, you could (assuming that IF, ZEROP, LIST, INCREMENT, and DECREMENT are already defined) have a function
(PARTIAL-ADD a b) -> (IF (ZEROP a)
b
(LIST (DEC a) (INC b)))
(Note that these are transformations in a quasi-lambda-calculus notation, not actual Lisp operations. Basically, here I am making an expansion, replacing (PARTIAL-ADD a b) with the expression on the right.)
If we then take
(PARTIAL-ADD (Y PARTIAL-ADD)) - > ADD
and apply that to , say, 2 and 2, we get
(ADD 2 2) ->
((PARTIAL-ADD (Y PARTIAL-ADD)) 2 2)
I was going to continue the expansion but decided that I wasn't quite ready to go that far down the rabbit hole right now. If you really want to go into it further, someone can go over it with you in more detail later.