天天看點

從基礎概念解釋“僞”遞歸

摘要:老趙提了個“僞”遞歸的說法

=========================

  第一次列印出的120是正确的結果。不過facAlias從fac那裡“接過”了使用Lambda表達式構造的委托對象之後,我們讓fac引用指向了新的匿名方法x => x。于是facAlias在調用時:

  自然就不對了。

=============================

老趙其實解釋得也很清楚:

這個Lambda表達式構造的“委托對象”在調用時,它會去尋找fac這個引用所指向的委托對象。請注意,這裡是根據“引用”去找“對象”,這意味着Lambda表達式構造的委托對象在調用時,fac可能已經不再指向當初的委托對象了。

我了解的意思就是老趙說facAlias的定義雖然看起來很像遞歸,但是本質上不是遞歸,是以一時興起起個名字叫“僞”遞歸

結果人家鶴沖天不幹了,覺得老趙對于Lambda遞歸有偏見。

================================== 

public static Func<int, int> Fibonacci = n => n > 1 ? Fibonacci(n - 1) + Fibonacci(n - 2) : n;

是計算Fibonacci數列的,注意上這句代碼中用了“static”,可以編譯通過,絕對沒有問題!老趙回複中說不用static無法編譯通過,于是我又給出了以下代碼(以下稱為代碼二):

    Func<int, int> Fibonacci = null;

    Fibonacci = n => n > 1 ? Fibonacci(n - 1) + Fibonacci(n - 2) : n;

代碼二就是老趙随筆中開始處的那兩行被稱為“僞”遞歸代碼,所說的朋友自然就是我了!

===================================

呵呵,人家老趙沒說代碼二是僞遞歸呀。facAlies才是呢。并且老趙的希望不是僅僅構造一個遞歸,而是希望

我的想法是,既然使用“Lambda表達式來構造一個遞歸函數”的難點是因為“我們正在構造的東西是沒有名字的”,是以“我們無法調用自身”。那麼,如果我們換種寫法,把我們正在調用的匿名函數作為參數傳給自己,那麼不就可以在匿名函數的方法體中,通過調用參數來調用自身了嗎?

以及從這個出發點開始擴充下去的東西

這樣我們能清楚些,當我們執行委托的時候,會使用Invoke(args)來調用方法體,看清楚,是Invoke方法,并不是委托自己哦,這一點已經偏離了遞歸的概念了。

這是個原則性問題,我的跟帖也就是沖這個去的

其實很多問題根本不需要IL來湊熱鬧。

最後,使用最基礎的記憶體堆棧結構概念來解釋老趙的代碼

回顧基本概念,值類型、引用類型。

Func<int, int> fac = null;

fac = x => x <= 1 ? 1 : x * fac(x - 1);

Func<int, int> facAlias = fac;

fac = x => x;

Console.WriteLine(facAlias(5)); // 20

第一行,在記憶體中的情況如下

從基礎概念解釋“僞”遞歸

第二行

從基礎概念解釋“僞”遞歸

第三行

從基礎概念解釋“僞”遞歸

第四行

從基礎概念解釋“僞”遞歸

第五行的運作結果自然就是老趙說的:

facAlias(5) <— facAlias是x => x <= 1 ? 1 : x * fac(x – 1)

= 5 <= 1 ? 1 : 5 * fac(5 - 1)

= 5 * fac(4) <— 注意此時fac是x => x

= 5 * 4

= 20

是以facAlias不是一個遞歸Lambda表達式,是以可以認為是一種“僞遞歸”

這裡的fac是一個如假包換的遞歸

=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+

最後謝謝各位觀賞

本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接配接。

從基礎概念解釋“僞”遞歸

本文轉自徐少俠部落格園部落格,原文連結:http://www.cnblogs.com/Chinese-xu/archive/2009/09/02/1558547.html,如需轉載請自行聯系原作者

繼續閱讀