吃了大力丸的Ruby:unfold的實現

最近奇忙。從早到晚工作。別說寫博客,連讀博客都 沒有時間。雖然一直想八卦一下JavaScript那濃眉大眼的也背叛革命了這件大事,卻抽不出空。不過看到這麼精彩的代碼,還是忍不住轉載。

起因是這樣的:大家都熟悉fold函數,也就是Ruby裏常用的inject()函數:給出起始值,把某個Collection裏的值疊加上去。比如說,給出起始值0,累加數組[1, 2, 3, 4, 5]: 

[, , , , ].inject(){|| sum = sum + n}

有了fold,便有相反的unfold:把單個的對象映射到Collection上。比如說 

.unfold { || n-  n ==  }.inspect => [, , , , , , , , , ]
.class.unfold(&).inspect => [, , , ]

它的實現也出奇地漂亮:通過遞歸把unfold調用改寫爲數組操作。頗有term rewriting系統的風範: 

   &block
block.call().unfold(&block).unshift()
 &block
[]
用例子最容易說明這段實現的驚豔之處。我們手工執行3.unfold{|n| n - 1 unless n ==1}:
  1. 我們用block指代上式裏的{|n| n - 1 unless n == 1}。根據unfold的定義,上式變爲block.call(3).unfold(&block).unshift(3)
  2. 執行block.call(3)得到2,於是我們得到2.unfold(&block).unshift(3)
  3. 根據定義,我們得到block.call(2).unfold(&block).unshift(2).unshift(3)
  4. 執行block.call(2),我們得到1.unfold(&block).unshift(2).unshift(3)
  5. 再根據定義,我們得到block.call(1).unfold(&block).unshift(1).unshift(2).unshift(3)
  6. block.call(1)的結果是nil,所以我們得到nil.unfold(&block).unshift(1).unshift(2).unshift(3)
  7. nil早準備好了unfold的定義,於是我們得到[].unshift(1).unshift(2).unshift(3),也就是[3, 2, 1]了。

現在胃口被吊起來的老大們可以看這裏的討論了。

 
發佈了245 篇原創文章 · 獲贊 33 · 訪問量 323萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章