@chi's answer是關於Haskell評估模型的技術差異。我希望能給你一些關於這種類型編程哲學的見解。
在分類理論中,我們通常使用「達到同構」的對象。你的Bar
當然是同構於(String, Int, Char)
,所以從分類的角度來看它們是一回事。
bar_tuple :: Iso' Bar (String, Int, Char)
bar_tuple = iso to from
where to (Bar s i c) = (s, i, c)
from (s, i, c) = Bar s i c
在某種意義上元組是產品類型的柏拉圖式的形式,因爲它們沒有任何意義超越是完全不同的值的集合。所有其他產品類型可以映射到一個普通的舊元組。
那麼爲什麼不使用元組無處不在,當所有的Haskell類型的最終歸結到的乘積之和?這是關於溝通。正如Martin Fowler所說,
任何傻瓜都可以編寫計算機可以理解的代碼。好的程序員編寫人類可以理解的代碼。
名字是很重要的!寫下自定義產品類型像
data Customer = Customer { name :: String, address :: String }
灌輸與意思閱讀代碼的人的類型Customer
,不像(String, String)
這只是意味着「兩個字符串」。當你想通過隱藏數據的表示和使用智能構造執行不變
自定義類型特別有用:
newtype NonEmpty a = NonEmpty [a]
nonEmpty :: [a] -> Maybe (NonEmpty a)
nonEmpty [] = Nothing
nonEmpty xs = Just (NonEmpty xs)
現在,如果你不導出NonEmpty
構造,就可以迫使人們通過nonEmpty
智能構造函數。如果有人給你一個NonEmpty
價值,你可以安全地假設,它至少有一個元素。
當然你也可以代表Customer
作爲引擎蓋下一個數組和揭露喚起名爲場存取,
newtype Customer = Bar (String, String)
name, address :: Customer -> String
name (Customer (n, a)) = n
address (Customer (n, a)) = a
,但是這並不能真正給你買得多,但它現在便宜Customer
轉換爲一個元組(比如說,如果你正在寫性能敏感的代碼與面向元組的API的工作)。
如果你的代碼是爲了解決特定的問題 - 這當然是寫代碼的整點 - 它支付不只是解決問題,但使它看起來像你已經解決了這一點。有人 - 也許你在幾年 - 將不得不讀取這些代碼並沒有理解它是如何工作的先驗知識。自定義類型是這方面非常重要的溝通工具。