莊周夢蝶

          生活、程序、未來
             :: 首頁 ::  ::  :: 聚合  :: 管理
              Lich Ray寫了個帖子《函數式編程語言曲高和寡?》,用快速排序的例子來說明函數式編程在表達思想方面比命令式語言更容易,其實這一點毋庸置疑,如果你正在讀或者讀過SICP的話。文中給了haskell、scheme和javascript的實現例子,我也湊趣寫了個Erlang版本,haskell我不了解就不說了,其他實現分別如下:
          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中的主要作用:分解復雜數據結構以便賦值和條件分支的分派。
              扯遠些可以談到模式匹配是以“like-a”來代替消息分派在傳統命令式語言中嚴格的“is-a”,這也跟現實世界的情況更為符合,現實世界中我們對事物的判斷都是模糊。而這一點,不正是“Duck-Typing”?傳統語言對于對象的類型(type)判斷來源于嚴格確定對象是什么類(class),不是這個類它就沒有相應的方法,而事實上類與類型這兩個概念并不是一致的,對象的類型更應該根據對象能夠做什么來決定。扯遠了,這只是我讀《失蹤的鏈環》得來的感受,如果對模式匹配還有懷疑的話,讓我們回到這個例子的Erlang版本,代碼中我們調用了兩次filter進行全表掃描,以便得到根據H切割的大小兩個部分,這在性能上有不小的影響,那么我們能不能只進行一次全表掃描呢,返回結果是“大小”兩個部分,看看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所要滿足的運行場景有緊密關系,當系統發生錯誤時,就可以從原來的值重新啟動任務,而不用擔心由于變量值的變化導致系統恢復困難。




          主站蜘蛛池模板: 石河子市| 杭锦后旗| 安远县| 兴义市| 宣城市| 金昌市| 杭锦后旗| 巧家县| 柞水县| 东宁县| 广昌县| 洪泽县| 东安县| 丰城市| 内江市| 饶平县| 通山县| 济源市| 松原市| 阿拉善左旗| 松滋市| 沙河市| 清涧县| 浦城县| 临汾市| 两当县| 临颍县| 武清区| 沙坪坝区| 于都县| 富蕴县| 江山市| 石阡县| 扎赉特旗| 东台市| 洞头县| 晋江市| 茶陵县| 黑水县| 渝北区| 上高县|