把簡單的javascript改成functional programming的風格練習
Fri, 02 May 2008 20:00:51 +0800繼續練習把javascript改成functional programming的風格...
先試著把之前寫的依照我需要的格式產生表格的javascript改成pure functional programming的風格,包含currying以及把所有敘述盡量改成lambda calculus。
首先是這個產生表格的函數最早的模樣:
function draw(target, values) { var row0 = target.insertRow(-1); for (var j=0; j<values.length; j++) { var cell0 = row0.insertCell(-1); cell0.innerHTML += (j+1); } var row0 = target.insertRow(-1); for (var j=0; j<values.length; j++) { var cell0 = row0.insertCell(-1); cell0.style.fontSize = 12; cell0.innerHTML += values[j]; } } var t = document.getElementById("target"); draw(t, [0.23,0.351,0.3481,1.382]);
接著先做一次currying,讓這個函數可以用每次接受一個參數的方式來操作:
function drawc(target){ return function(values) { var row0 = target.insertRow(-1); for (var j=0; j<values.length; j++) { var cell0 = row0.insertCell(-1); cell0.innerHTML += (j+1); } var row0 = target.insertRow(-1); for (var j=0; j<values.length; j++) { var cell0 = row0.insertCell(-1); cell0.style.fontSize = 12; cell0.innerHTML += values[j]; } }; } drawc(document.getElementById("target"))([0.23,0.351,0.3481,1.382]);
其實沒做多大更動,只是把之前的function body改成一個以第二個參數為唯一參數的匿名函數,然後回傳這個匿名函數。上面的例子drawc函數會回傳一個函數,我直接就用([0.23,0.351,0.3481,1.382])呼叫這個函數並且傳入values參數,實際應用時可以把這個動作再推遲,例如傳給另一個函數處理,或是先存起來等需要的時候再傳values參數給他完成動作等等。
接下來把整個function body改寫成lambda calculus:
function drawcl(target){ return function(values) { (function(row0){ (function(j){ if(j<values.length) { (function(cell0){ cell0.innerHTML += j+1; })(row0.insertCell(-1)); arguments.callee(j+1); } })(0); })(target.insertRow(-1)); (function(row0){ (function(j){ if(j<values.length) { (function(cell0){ cell0.style.fontSize = 12; cell0.innerHTML += values[j]; })(row0.insertCell(-1)); arguments.callee(j+1); } })(0); })(target.insertRow(-1)); }; } drawcl(document.getElementById("target"))([0.23,0.351,0.3481,1.382]);
從這個過程可以看出幾個修改的原則:
- 把變數改成匿名函數的參數,把與這個變數相關的運算移到匿名函數裡面,變數名變成參數名,然後等號(assign)右側的敘述放在呼叫函數的參數運算中。
- 把iteration的運算改成匿名函數的遞迴,控制條件當作匿名函數的參數傳給他,然後在函數中判斷是否要停止遞迴
- 額外的技巧,與fp無關:在javascript中,可以利用arguments.callee來讓匿名函數做遞迴
恩恩,經過嘗試以後,感覺並不是很困難。有空的話再來做更複雜的例子。
以下是在表格border="1" cellpadding="1" cellspacing="0" id="target"的條件中測試跑出來的表格內容:
沒意外的話,應該三個畫面都一樣。