型別變數
型別變數是型別簽名中的非大寫字母名稱。與他們的大寫對手不同,例如 Int
和 String
,它們不代表任何型別,而是任何型別。它們用於編寫可以在任何型別或型別上執行的泛型函式,對於通過 List
或 Dict
等容器編寫操作特別有用。例如,List.reverse
函式具有以下簽名:
reverse : List a -> List a
這意味著它可以在任何型別值的列表上工作,所以 List Int
,List (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 = Int
和 b = Int
。但是,如果 map
有一個像 map : (a -> a) -> List a -> List a
這樣的型別簽名,那麼它只適用於在單一型別上執行的函式,並且你永遠無法通過使用 map
函式來改變列表的型別。但由於 map
的型別簽名有多個不同的型別變數 a
和 b
,我們可以使用 map
來改變列表的型別:
isOdd : Int -> Bool
isOdd x =
x % 2 /= 0
> List.map isOdd
<function> : List Int -> List Bool
在這種情況下,a = Int
和 b = Bool
。因此,為了能夠使用可以獲取和返回不同型別的函式,必須使用不同的型別變數。