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