不用靜態型別函數語言程式設計語言的十大理由

oschina發表於2013-06-19

  你厭煩函數語言程式設計麼?我也煩,我真想呼籲那些想我一樣明智的人遠離這種語言。

  這裡要澄清一點,我指的這種靜態型別函數語言程式設計語言,包括那種型別推斷或者靜態預設等等。實際上,就是Haskell和ML—family(包括Ocaml和F# )

  理由一: 不想跟潮流

  像大多數程式設計師一樣,我懷舊且討厭學習新東西。

  這是我選擇混IT這行的原因。

  我不跟風的原因跟其它“程式猿“一樣,靜觀其變,等該產品差不多了且能看到其前景。

  對我來說,函數語言程式設計這東西太新了,我討厭新東西。

  是的,有些傢伙已經把ML和Haskell跟他們之前最喜歡的Java&PHP作比較了。

  但最近我只聽說過Haskell,他們所說的對我都是廢話。

  看看新寵F#語言。已經有七年了,彼得的大作。當然,這在業界來說已經生存不少時間了,但相對於網際網路的歷史,七年只是一眨眼。

  所以,像我所說的那樣,我會謹慎的小心的觀察每個internet潮流,函式式式程式設計或許只是浮雲。

  理由二: 我按程式碼行數算工資

  你怎麼想的我不知道,但是隨著我寫的程式碼越多,我就越有成就感,效率很高。如果一天能快速完成500行程式碼,那就可以說你乾的漂亮。每天的任務很繁重,而且boss眼裡你也總是忙忙碌碌的。

  但是當我拿函數語言程式設計語言和那些老牌語言例如C去比較時,程式碼少的讓我吃驚。

  就拿下面這段程式碼為例:

public static class SumOfSquaresHelper
{
   public static int Square(int i)
   {
      return i * i;
   }

   public static int SumOfSquares(int n)
   {
      int sum = 0;
      for (int i = 1; i <= n; i++)
      {
         sum += Square(i);
      }
      return sum;
   }
}

  比比下面的:

let square x = x * x
let sumOfSquares n = [1..n] |> List.map square |> List.sum

  十七行的程式碼只剩下2行了,想想如果這種變化發生在整個工程裡面會有什麼後果。

  如果我們使用這種方法,估計我的程式碼產量會直線下降--這不是我能忍受的。

  理由三:我喜歡大括號

  還有一點使我不想喜歡這種語言的原因是,我不明白這些與語言要把大括號去掉。去掉大括號還能叫程式語言麼?看下我的意思。這是帶大括號的程式碼:

public class Squarer
{
    public int Square(int input)
    {
        var result = input * input;
        return result;
    }

    public void PrintSquare(int input)
    {
        var result = this.Square(input);
        Console.WriteLine("Input={0}. Result={1}", input, result);
    }
}

  這個則是去掉大括號的相同的程式碼:

type Squarer() = 

    let Square input =
        let result = input * input
        result

    let PrintSquare input =
        let result = Square input
        printf "Input=%i. Result=%i" input result 

  看看差別吧,你怎麼想我不知道,但是我真心覺得第二種語言有點像垃圾,就像漏掉了什麼東西似得。

  實話說,如果沒有大括號給我指引,我總覺得少了些東西。

  理由四:我喜歡看到明確的型別

  函式式語言的支持者聲稱,型別推斷使程式碼更清潔,因為任何時候你都無須用型別宣告干擾您的程式碼。

  好吧,碰巧,我喜歡看型別宣告。如果我不知道每個引數的精確型別,我會覺得不舒服。這就是為什麼Java 是我最喜歡的語言。

  這是一個某些ML-ish程式碼的函式簽名。不需要型別宣告,所有型別自動推斷。

let GroupBy source keySelector = 
    ... 

  這是C#的類似功能程式碼的函式簽名,帶有明確的型別宣告。

public IEnumerable<IGrouping<TKey, TSource>> GroupBy<TSource, TKey>(
    IEnumerable<TSource> source,
    Func<TSource, TKey> keySelector
    )
    ...

  在這方面我或許是屬於少數派,但我更喜歡第二個版本的說法。知道返回值的型別是IEnumerable<IGrouping<TKey, TSource>>對我而言極為重要。

  確實,編譯器會為你檢查它的型別,並在型別不匹配的時候提醒你。但為什麼要讓編譯器代替你做你能做的工作呢?

  好吧,我承認如果你使用了泛型,匿名,返回值為函式的函式,以及其它一切新奇的東西,那麼你的型別宣告將變得複雜又難以理解。而這使得正確判斷型別變得非常困難。

  但對此我有個簡單的彌補辦法——不使用泛型而且不要傳遞函式,你的簽名將變得簡單許多。

  理由五:喜歡修復bug

  對我來說,找出bug除錯bug,就想狩獵一樣刺激。如果在產品系統中存在這個bug,我更興奮,因為那使我有一種我是英雄的錯覺。但是當我看了這種靜態型別函數語言程式設計之後,尋找bug就變得困難多了。太不爽了。

  理由六: 我生活於除錯程式之中

  論及修復bug,我可是花費每天的大部分時間在除錯程式、程式碼單步執行中的。沒錯,我知道應該使用單元測試,但說起來容易做起來難,對不?

  不管怎樣,通過這些靜態型別的函式式語言,如果你的程式碼編譯通過了,一般它就能正常執行

  我聽說你不得不耗費許多時間在型別匹配上面,但一旦完成它又編譯成功,就沒有什麼需要除錯的了。這裡面哪裡有樂趣呢?

  這使我轉向到……

  理由七:我不想死扣每個細節

  確保所有的型別匹配合適聽起來就讓我覺得累

  事實上,我知道你得被迫去考慮各種可能出現的情況,所有可能的錯誤,所有別的可能出錯的事情。而且你得至始至終去做這些——決不能偷懶也不能推脫到到後面。

  我更喜歡在一個相對愉快的環境下工作,然後再屁顛屁顛的去修復bug

  理由八:我喜歡檢查空值

  我十分樂意為每個方法檢查空值。那會給我很大的安全感,我知道我的程式碼執行結果是安全的

void someMethod(SomeClass x)
{
    if (x == null) { throw new NullArgumentException(); }

    x.doSomething();
}

  哈哈!開個玩笑!當然我不能總是要在每個地方都要放置檢查空值的程式碼這種事情來打斷我。這點我從來沒有落到實處。

  我是僅去處理由NPE造成的災難,而且即使我是在產品釋出之後幾個星期後才發現那些問題,對業務也沒有影響。所以我不懂為啥這也算是個大問題。

  理由九:我喜歡用設計模式

  第一次接觸到設計模式是在《Design Pattern book》(由於一些原因,被稱為“四人幫”,我實在搞不懂),自從那以後我就費勁心機用它來解決各種問題。這確實能使我的程式碼看起來嚴謹並且有團隊性,給我的boss留下了很深的印象。

  但是我沒有絲毫注意在函式設計中的這種模式。如果沒有策略、工廠模式、裝飾者模式、代理模式等,你怎麼能整理好有用的材料。

  也許函數語言程式設計沒有注意到這些!

  理由十: 它太數學範了

  這兒有更多關於計算平方和的程式碼。這個方法太難理解了,因為其中都是怪異的符號。

ss=: +/ @: *:

  哎呀,抱歉!搞錯了。那是 J語言程式碼

  可我確實聽說有些函式功能程式使用奇怪的符號,像<*>和>>=以及晦澀的概念“單元”(monads)和“仿函式”(functors)。

  我不知道為什麼寫函式的人不能堅持用我已經知道的東西——明白的符號如++和!=以及簡單的概念“繼承”和“多型”。

  後記:我不理解

  你知道麼,我理解不了它!我不懂為什麼這種函數語言程式設計語言會有用!

  現在我讀到一些帖子如“你需要了解的事情都在一個網頁上”。但是對我來說那太簡短了。

  我一直在找更深層次的一些東西—能夠讓我啃的知識。

  不,不要說我應該讀一些教科書或者去看一些經典的例子,然後寫下程式碼。我想不通過那些方法來體驗一下。

  我不想僅僅是為了學習新的範例而改變我自己我自己的道路

  英文原文:Ten reasons not to use a statically typed functional programming language

相關文章