[Erlang 0056] 用fun在Erlang Shell中編寫尾遞迴 Ⅱ

來源:互聯網
上載者:User

 之前研究了一個問題"[Erlang 0050]用fun在Erlang Shell中編寫尾遞迴",一直對這個問題保持著關注;最近在搜尋引擎裡找到同一個問題,題目足夠清晰calling fun() from fun() 它提供了另外一種解決解決方案: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

不錯吧,不過我們的目標是在shell裡面直接實現尾遞迴,所以要動手簡單改造一下 

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> 

問題還沒有結束,對於兩個參數的怎麼辦呢?Y函數比較直觀,可以修改為:


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

  當然多個參數我們可以使用apply mfa的方式來處理多個參數的情況.同時Y方法也可以放在user_default裡面方便後續使用.實踐之後說一點理論吧,這種解決方案是使用了Y combinator可能最近你已經頻繁接觸到這個名字,比如在IT新聞,比如在<<駭客與畫家>>,它本身是一個數學概念,那麼我們從維基百科開始:

英文維基

Fixed-point combinator http://en.wikipedia.org/wiki/Fixed-point_combinator

Y combinator: http://rosettacode.org/wiki/Y_combinator

中文維基

不動點組合子 http://zh.wikipedia.org/wiki/%E4%B8%8D%E5%8A%A8%E7%82%B9%E7%BB%84%E5%90%88%E5%AD%90

不動點 http://zh.wikipedia.org/wiki/%E4%B8%8D%E5%8A%A8%E7%82%B9

λ演算 http://zh.wikipedia.org/wiki/%E6%97%A0%E7%B1%BB%E5%9E%8B_lambda_%E6%BC%94%E7%AE%97


 

我們理順一下裡面的邏輯關係,從不動點開始:

在數學中,函數的不動點或定點是指被這個函數映射到其自身一個點.例如,定義在實數上的函數f,f(x)=x2-3x+4則2是函數f的一個不動點,因為f(2)=2.也不是每一個函數都具有不動點。例如定義在實數上的函數,f(x)=x+1就沒有不動點。因為對於任意的實數,x永遠不會等於x+1。用畫圖的話來說,不動點意味著點(x,f(x))在直線y=x上,或者換句話說,函數f的映像與那根直線有共點。上例f(x)=x+1的情況是,這個函數的映像與那根直線是一對平行線.

 我用wolframalpha.com繪製了f(x)=x2-3x+4的函數圖:

   接下來我們看不動點組合子(Fixed-point combinator,或不動點運算元)是計算其他函數的一個不動點的高階函數.函數 f 的不動點是一個值 x 使得 f(x) = x.例如,0 和 1 是函數 f(x) = x2 的不動點,因為 02 = 0 而 12 = 1.鑒於一階函數(在簡單值比如整數上的函數)的不動點是個一階值,高階函數 f 的不動點是另一個函數 g 使得 f(g) = g.那麼,不動點運算元是任何函數 fix 使得對於任何函數 f 都有f(fix(f)) = fix(f).不動點組合子允許定義匿名的遞迴函式.

然後接下來是Y combinator(Y組合子)在無類型 lambda 演算中眾所周知的(可能是最簡單的)不動點組合子叫做 Y 組合子.它是 Haskell B. Curry 發現的,定義為

Y = λf.(λx.f (x x)) (λx.f (x x))  %%用一個例子函數 g來展開它,我們可以看到上面這個函數是怎麼成為一個不動點組合子的
Y g = (λf.(λx . f (x x)) (λx . f (x x))) g
Y g = (λx. g (x x)) (λx . g (x x))          %%λf 的 β-歸約 - 應用主函數於 g
Y g = (λy. g (y y)) (λx . g (x x))          %%α-轉換 - 重新命名約束變數
Y g = g ((λx. g (x x)) (λx . g (x x)))     %%λy 的 β-歸約 - 應用左側函數於右側函數
Y g = g ( Y g)   %% Y 的定義 

  這個!?在程式設計語言裡面怎麼實現呢?看一下http://rosettacode.org/wiki/Y_combinator 這裡羅列了大多數語言對Y combinator的實現,比如C#版本: 

delegate Func<int , int > Recursive(Recursive recursive);
void Main()
{
        Func<Func<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));
}

  不過注意一下Erlang版本的實現,上面提供了另外一種實現方式(只不過在下面這種實現中,怎麼使用多個參數呢?):

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


  沿著Y Combinator這個線索,可以找到更多的資料,
[PDF]  The Why of Y - Dreamsongs  

[1] Y Combinator in Erlang

[2] Deriving the Y Combinator in Erlang  (原文已經被牆,這是我拷貝出來的副本)

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.