haskell學習筆記(8)-haskell的類型系統

類型推導

haskell因爲支持類型推導,所以大多數時候不用顯式寫出類型聲明,但是如果要寫庫的話,最好是寫上類型聲明,可以當做文檔使用,看上去一目瞭然。

haskell的類型推導比大部分語言要強不少,例如和同樣有類型推導的kotlin相比,kotlin並不支持傳入參數的自動推導
例如

//a b參數都要寫明類型
fun max(a:Int,b:Int)=if (a>b) a else b
//這樣是編譯不過的
fun max(a,b)=if (a>b) a else b
//kotlin類型推導基本上只能用作聲明變量
var a=10;

可以看出,kotlin的類型推導基本上只是一個簡單的根據值推斷出類型的過程

我們看看haskell的

--這樣完全可以
max' a b=if a>b then a else b

所以haskell的類型推導還包括了上下文的類型推導,實際上我們在ghci裏查看他的類型,會發現結果是,我們先將Ord看成一個接口,所以haskell可以通過上下文自動推導出需要傳入的值需要實現Ord接口(一個可以比較的接口)

這種上下文的類型推導,一般在命令式語言裏很難實現,而在函數式語言裏相對容易,因爲函數式語言每個語句都有值,可以使用動態分析來得到返回值,而且函數式語言沒有複雜的控制結構,方便分析。

max' :: (Ord a)=>a->a->a

當然,雖然haskell的類型推導很強大,不過在函數比較複雜的情況下,如果不寫明類型,很容易讓函數使用者無所適從,因爲單看語句很難明白要傳入什麼,會返回什麼。

類型系統

我們往常在靜態語言裏寫代碼的時候,都是將類型聲明和函數本身混合在一起,例如下面這個函數,即包括了訪問控制符public,又包括了函數名max,參數名a,b

    public int max(int a,int b)
    {
        return a>b?a:b;
    }

在接觸haskell之前,我覺得這樣挺自然的,不過接觸haskell的類型和函數實現分開寫之後,感覺這樣反而會使代碼更清晰。

--類型聲明
max' :: (Ord a)=>a->a->a
--實現
max' a b=if a>b then a else b

我們不斷在新語言里加一些新結構,語法糖,很大原因就是希望代碼看起來更具結構性,更簡潔,例如for來替換while,switch來替換if else,那其實我個人覺得,將類型聲明和代碼主體分開寫,也是一種使代碼更簡潔的方法。不知道大家怎麼看。

haskell因爲有不全調用以及高階函數的存在,所以他的類型聲明第一次看的時候都會略顯怪異,每個參數都是用->來間隔,不過習慣了高階函數就好。

addThree :: Int -> Int -> Int -> Int
addThree x y z = x + y + z
--其實就等價於
addThree :: Int ->( Int -> (Int -> Int))
addThree x y z = x + y + z

如果寫的不是實際的類型而是類型變量,其實就和其他語言裏的泛型差不多

--haskell
ghci> :t head
head :: [a] -> a

--等價的java聲明
public<T> T head(T[] array){}

再看下面這個,其實也和java泛型加類型參數的上限差不多

ghci> :t (==)
(==) :: (Eq a) => a -> a -> Bool
--等價的java聲明 一直想吐槽設定java類型參數的接口限制用的是extends關鍵字而不是implement
public<T extends Eq> T head(T[] array){}

雖然我看的幾本書上都說haskell的類型聲明typeclass比其他語言的泛型強很多。。其實我還是覺得差不多滴,目前看來,haskell比其他語言強很多的特性基本上就是,列表推導,高階函數 ,其他的特性基本上都是這兩個引申出來的。


歡迎關注我的github
https://github.com/luckyCatMiao

發佈了108 篇原創文章 · 獲贊 64 · 訪問量 8萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章