第二個明顯失敗,因爲"I am not a number!"
在該往返中拋出錯誤。有很多原因爲什麼在純代碼中拋出錯誤是危險的,而且類型類危險會繼續並污染任何曾經導入代碼的人的代碼。
您可能會指出,這只是因爲並非所有字符串都是有效數字。好像fromSI . toSI
總是麻煩,但toSI . fromSI
應該工作。也許它隻影響像例化instance Num String
這樣的東西,而如果我們改爲使用我們的(toSI, froSI)
對來推導instance
的Integer
那String
我們會處於一個好位置。 也許吧。
讓我們試試吧。 String
是Monoid
一個實例,看起來像這樣
instance Monoid [a] where -- if a ~ Char then this is String
mempty = []
mappend as bs = as ++ bs
如果我們通過mappend = toSI . mappend . fromSI
實施mappend
它爲我們提供了「串聯整數」像
(1 <> 2) <> 3 == 123
1 <> (2 <> 3) == 123
(0 <> 1) <> 1 == 11
0 <> (1 <> 1) == 11
,如果我們仔細定義"" -> 0
而不是使它失敗,那麼我們也可以得到一個有用的mempty
。
mempty = toSI mempty
這似乎應該工作得很好。它真的是Integer
Integer
繼承其「單向同構」與String
(想想爲什麼我必須在這裏使用Integer
,而不是Int
)。更具體地說,我們無法通過從Monoid
類型類中的函數構建的任何測試來區分toSI (fromSI n)
和n
,所以它足夠「足夠」來進行此映射。
但是後來我們碰到了另一個問題。 Integer
已經有一個Monoid
實例。它已經擁有了其中的約10%,最流行的是乘法和加法
instance Monoid Integer instance Monoid Integer
mempty = 0 mempty = 1
mappend = (+) mappend = (*)
所以,我們通過挑選這些情況中的任何一個是規範類型類的實例含半幺羣失去了大量的信息。 Integer
通過它的「單向同構」(又名「縮回」)與String
變成Monoid
更加準確,但也可以通過剝離來增加,但也可以通過剝離來增加乘法。
我們真的要保持信息的周圍這就是爲什麼Monoid
包定義之類的東西Sum
和Product
這表明該Integer
一直專注於只使用其Addition
性能。
就是這樣,在一天結束時,您完全可以解決類型實例超出同構的問題。通常情況下,類型具有很多可以以這種方式濫用的同構和縮進,並且很難有真正的規範,守法的實例。當你找到一個代碼時,通常值得把代碼稅明確寫出來,即使你最終使用同構來完成。
當沒有你有一個像newtype
文書規範的選擇和庫的快速訪問哪些只是「下面」你newtype
層全部從普通GeneralizedNewtypeDeriving
擴展出路的Control.Newtype
package或直接啓發Iso
, au
and auf
擺和整個Wrapped
, ala
, alaf
機制lens
。
本質上,這個機制是爲了讓它更容易地討論各種同構,特別是那些由newtype
誘發的實例。
'get'? 'set'?我想你在問什麼與Haskell所謂的推測非常相關。你的意思是自動類型轉換,對吧?這不是一個好主意;它使您不能從雙向類型推演的好處中獲益,因爲這樣可以避免比一些顯式轉換函數可以合理引入的更多的樣板。 - 另外,這些是特別糟糕的例子,因爲這些類型甚至不是近似的同構。你會怎樣處理像'get「bla」:: Int','set(-1):: Bool'或set [1,2,3] :: Maybe Int'這樣的問題? – leftaroundabout
我認爲應該可以在編譯時用一個簡單的實例聲明替換聲明,所以類型系統應該保持不變,儘管我同意這個提議與Haskell的派生機制非常不相關;也許名稱變化是爲了。 – user1502040
什麼聲明應該被什麼取代?你能舉一個你想如何使用它的例子嗎? – leftaroundabout