天天看點

從一個小例子出發之ruby、scheme和Erlang的簡單比較

scheme:

(define (qsort ls)  

     (if (null? ls) '()  

         (let  

             ((x (car ls))  

             (xs (cdr ls)))  

             (let   

                 ((lt (filter (lambda (y) (< y x)) xs))  

                 (st (filter (lambda (y) (>= y x)) xs)))  

                 (append (qsort lt) (list x) (qsort st))))))  

javascript:

    // 把要用到的表達式抽象出來  

    array.prototype.head = function () {  

        return this[0];  

    }  

    array.prototype.tail = function () {  

        return this.slice(1);  

   array.prototype.filter = function (proc) {  

       var tmparr = [];  

       for (var i = 0; i < this.length; i++)  

       if (proc(this[i]) == true)  

           tmparr.push(this[i]);  

       return tmparr;  

   }  

   array.prototype.qsort = function () {  

       if (this == false) return []  

        var x, xs, lt, st  

       x = this.head()  

        xs = this.tail()  

        lt = xs.filter(function (y) {return y < x})  

        st = xs.filter(function (y) {return y >= x})  

        return lt.qsort().concat([x], st.qsort())  

用erlang的話,erlang的list其實跟scheme的list是一樣的,甚至連定義的基本高階函數都一樣:map,filter,append等等,利用lists子產品提供的filter和append,我們可以寫出:

    qsort([])->[];  

    qsort([h|t])->  

        lt=lists:filter(fun(e)->e<h end,t),  

        st=lists:filter(fun(e)->e>=h end,t),  

    lists:append(qsort(lt),lists:append([h],qsort(st))).  

    我們來比較下scheme和erlang版本,兩者最顯著的不同是,scheme使用了條件語句if,而erlang卻是通過模式比對來代替條件分支判斷。同樣,在list的分解上面,erlang也是利用了規則比對來代替car,cdr函數,從這裡可以看出規則比對在erlang中的主要作用:分解複雜資料結構以便指派和條件分支的分派。

sort([]) -> [];

sort([pivot|rest]) ->

   {smaller, bigger} = split(pivot, rest),

   lists:append(sort(smaller), [pivot|sort(bigger)]).

split(pivot, l) ->

split(pivot, l, [], []).

split(pivot, [], smaller, bigger) ->

{smaller,bigger};

split(pivot, [h|t], smaller, bigger) when h < pivot ->

split(pivot, t, [h|smaller], bigger);

split(pivot, [h|t], smaller, bigger) when h >= pivot ->

split(pivot, t, smaller, [h|bigger]).

    這幾行代碼充分展現了模式比對的威力,不過erlang其實有内置的方法partition用于切割list的,這裡隻是為了展現模式比對,是以上面的代碼可以改為:

sort([]) -> [];

sort([pivot|rest]) ->

{smaller, bigger} = lists:partition(fun(e)->e<pivot end, rest),

lists:append(sort(smaller), [pivot|sort(bigger)]).

同樣的代碼改寫為ruby版本:

def qsort(array)

  arr=array.dup

  if arr==[]

    []

  else

    x=arr.shift

    smaller,bigger=arr.partition{|e| e<=x}

    qsort(smaller)+[x]+qsort(bigger)

  end

end

    ruby與erlang都有并行指派,但是ruby不支援模式比對。請注意ruby并沒有尾遞歸優化,是以上面的代碼在數組比較大的時候會導緻棧溢出,想用ruby做函數式程式設計應該盡量多使用循環和map,filter,collect等輔助高階函數。

    另外一個erlang與ruby、scheme比較重要的差別是erlang的變量隻能指派一次(或者說綁定),也就是single assignment。這個特點與erlang所要滿足的運作場景有緊密關系,當系統發生錯誤時,就可以從原來的值重新啟動任務,而不用擔心由于變量值的變化導緻系統恢複困難

。文章轉自莊周夢蝶  ,原文釋出時間2007 7 15

繼續閱讀