I have studied a problem "[Erlang 0050] using fun to write tail recursion in Erlang shell" and have been paying attention to this problem. Recently, I found the same problem in search engines, the question is clear enough. Calling fun () from fun () provides another solution: Y-Combinator!
%%That's easy, you need the Y-combinator!y(M) -> G = fun (F) -> M(fun(A) -> (F(F))(A) end) end, G(G). and then you define you fun with a fun wrapper like so:Fac -> fun (F) -> fun (0) -> 1; (N) -> N * F(N-1) end end.and call it like:(y(Fac))(5)120
Good, but our goal is to implement tail recursion directly in shell, so we need to make a simple transformation.
Eshell V5.9 (abort with ^G)1> Y=fun(F) ->1> G = fun(T) ->1> F(fun(X) -> (T(T))(X) end)1> end,1> G(G) end.#Fun<erl_eval.6.111823515>2> 2> Fac = fun (F) ->2> fun (0) -> 1;2> (N) -> N * F(N-1)2> end2> end.#Fun<erl_eval.6.111823515>3> 3> (Y(Fac))(5).1204> Fib = fun(F) ->4> fun(0) -> 0;4> (1) -> 1;4> (N) -> F(N-1) + F(N-2) 4> end4> end.#Fun<erl_eval.6.111823515>5> 5> (Y(Fib))(8).216>
The problem is not over yet. What should I do with the two parameters? The y function is intuitive and can be changed:
6> Y2=fun(F) ->6> G = fun(T) ->6> F(fun(Y, Z) -> (T(T))(Y, Z) end)6> end,6> G(G) end.#Fun<erl_eval.6.111823515>7> Func2=fun(F)->7> fun(X,Y) when Y<1000 ->io:format("~p,",[X+Y]), F(Y,X+Y); 7> (X,Y) -> done 7> end7> end.#Fun<erl_eval.6.111823515>8> 8> (Y2(Func2))(0,1).1,2,3,5,8,13,21,34,55,89,144,233,377,610,987,1597,done
Of course, we can use the apply MFA method to process multiple parameters. the y method can also be placed in user_default for later use. after practice, let's talk about the theory. This solution uses Y Combinator. Recently, you may have frequently come into contact with this name, for example, in it news, such as
English Wiki
Fixed-Point Combinator http://en.wikipedia.org/wiki/Fixed-point_combinator
Y Combinator: http://rosettacode.org/wiki/Y_combinator
Chinese Wiki
Fixed Point combination subhttp://zh.wikipedia.org/wiki/%E4%B8%8D%E5%8A%A8%E7%82%B9%E7%BB%84%E5%90%88%E5%AD%90
Fixed Point http://zh.wikipedia.org/wiki/%E4%B8%8D%E5%8A%A8%E7%82%B9
λ calculus http://zh.wikipedia.org/wiki/%E6%97%A0%E7%B1%BB%E5%9E%8B_lambda_%E6%BC%94%E7% AE %97
Let's straighten out the logical relationship fromFixed PointStart:
In mathematics, the fixed point or point of a function is a point mapped to itself by this function. for example, F, F (x) = x2-3x + 4, 2 is a fixed point of function f, because F (2) = 2. not every function has a fixed point. For example, f (x) = x + 1 has no fixed point for a function defined on a real number. For any real number, X will never be equal to x + 1. In terms of drawing, the fixed point means that the point (x, f (x) is on the straight line y = X, or in other words, the image of function f has a common point with the straight line. In the above example, f (x) = x + 1 is that the image of this function is a parallel line with that line.
I used wolframalpha.com to plot the f (x) = x2-3x + 4 function diagram:
Next let's take a lookFixed Point combination child(Fixed-point Combinator, or fixed point operator) is a higher-order function used to calculate a fixed point of other functions. the fixed point of function f is a value X, which makes f (x) = x. for example, 0 and 1 are the fixed points of function f (x) = x2, because 02 = 0 and 12 = 1. given that the fixed point of a first-order function (such as a function on an integer) is a first-order value, the fixed point of a higher-order function f is another function g that makes F (G) = g. then, the fixed point operator is any function fix so that F (fix (F) = fix (f) is available for any function f ). fixed Point combination sub-allowDefine anonymous recursive functions.
Next, Y Combinator (Y Combinator), which is well known in non-type lambda calculus (probably the simplest), is called Y Combinator. it is Haskell B. found by curry, defined
-
Y= λ F. (λ x. f (x) (λ x. f (x) % use an example function
GWe can see how the above function becomes a fixed point combination.
-
YG = (λ F. (λ x. f (x) (λ x. f (x) g
-
YG = (λ x. g (x) (λ x. g (x) % λ F's β-reduction-apply the primary function to G
-
YG = (λ y. G (y) (λ x. g (x) % α-conversion-Rename the constraint variable
-
YG = g (λ x. g (x) (λ x. g (x) % λ y's β-reduction-apply the left function to the right Function
-
YG = g (
YG) %
YDefinition
This !? How can we implement it in programming languages? Take a look at the http://rosettacode.org/wiki/Y_combinator here lists the implementation of Y Combinator in most languages, such as C # version:
Delegate func <int, int> recursive (recursive );
Void main ()
{
Func <int, int>, func <int, int>, func <int, int> Y =
F => (recursive) (G => (f (x => G (G) (X) (recursive) (G => F (x => G (G) (X ))));
VaR FAC = Y (F => X => x <2? 1: x * f (x-1 ));
VaR fib = Y (F => X => x <2? X: f (x-1) + f (x-2 ));
Console. writeline (FAC (6 ));
Console. writeline (FIB (6 ));
}
But pay attention to the implementation of Erlang, which provides another implementation method (but in the following implementation, how to use multiple parameters ?) :
Eshell V5.9 (abort with ^G)1> Y = fun(M) -> (fun(X) -> X(X) end)(fun (F) -> M(fun(A) -> (F(F))(A) end) end) end.#Fun<erl_eval.6.111823515>2> Fac = fun (F) ->2> fun (0) -> 1;2> (N) -> N * F(N-1)2> end2> end.#Fun<erl_eval.6.111823515>3> (Y(Fac))(5). 1204> 4> Fib = fun(F) ->4> fun(0) -> 0;4> (1) -> 1;4> (N) -> F(N-1) + F(N-2) 4> end4> end.#Fun<erl_eval.6.111823515>5> (Y(Fib))(8).
You can find more information along the clues of Y Combinator,
[PDF] the why of Y-dreamsongs
[1] Y Combinator in Erlang
[2] deriving the Y Combinator in Erlang)