型別變數

型別變數是型別簽名中的非大寫字母名稱。與他們的大寫對手不同,例如 IntString,它們不代表任何型別,而是任何型別。它們用於編寫可以在任何型別或型別上執行的泛型函式,對於通過 ListDict 等容器編寫操作特別有用。例如,List.reverse 函式具有以下簽名:

reverse : List a -> List a

這意味著它可以在任何型別值的列表上工作,所以 List IntList (List String),這些和其他任何一個都可以完全相同。因此,a 是一個可以代表任何型別的型別變數。

reverse 函式可以在其型別簽名中使用任何非大寫的變數名,除了少數特殊型別的變數名,例如 number(有關更多資訊,請參閱相應的示例):

reverse : List lol -> List lol

reverse : List wakaFlaka -> List wakaFlaka

只有當單個簽名中有不同的型別變數時,型別變數的名稱才有意義,例如列表中的 map 函式:

map : (a -> b) -> List a -> List b

map 從任何型別的 a 到任何型別的 b,以及包含某些型別 a 的元素的列表,並返回一些型別 b 的元素列表,它通過將給定的函式應用於列表的每個元素來獲取。

讓我們使簽名具體化,以便更好地看到這一點:

plusOne : Int -> Int
plusOne x = 
    x + 1

> List.map plusOne
<function> : List Int -> List Int

我們可以看到,在這種情況下,a = Intb = Int。但是,如果 map 有一個像 map : (a -> a) -> List a -> List a 這樣的型別簽名,那麼它只適用於在單一型別上執行的函式,並且你永遠無法通過使用 map 函式來改變列表的型別。但由於 map 的型別簽名有多個不同的型別變數 ab,我們可以使用 map 來改變列表的型別:

isOdd : Int -> Bool
isOdd x =
    x % 2 /= 0

> List.map isOdd
<function> : List Int -> List Bool

在這種情況下,a = Intb = Bool。因此,為了能夠使用可以獲取和返回不同型別的函式,必須使用不同的型別變數。