2013-08-29 49 views
1

我很抱歉,如果這個問題似乎病了深思熟慮的,但我不知道是否有可能定義一個一致的語義類似下面哈斯克爾:建議導出機制哈斯克爾

derive Num String from Int where 
    get = read 
    set = show 

derive Ord Bool from Integer where 
    get = fromEnum 
    set = toEnum 

derive (Monad, Functor) Maybe from [] where 
    get (Just x) = [x] 
    get Nothing = [ ] 
    set [x]  = Just x 
    set [ ]  = Nothing 

我沒有理由不這樣做,在某些情況下它似乎會減少樣板,但我不知道是否(如果是這樣,多麼容易)這可以實施。

編輯:

我的意圖是爲例如,第一個例子被替換爲這樣的東西:

instance Num String where 
    get = read :: String -> Int 
    set = show :: Int -> String 
    a + b = set $ get a + get b 
    a * b = set $ get a * get b 
    ... 
+3

'get'? 'set'?我想你在問什麼與Haskell所謂的推測非常相關。你的意思是自動類型轉換,對吧?這不是一個好主意;它使您不能從雙向類型推演的好處中獲益,因爲這樣可以避免比一些顯式轉換函數可以合理引入的更多的樣板。 - 另外,這些是特別糟糕的例子,因爲這些類型甚至不是近似的同構。你會怎樣處理像'get「bla」:: Int','set(-1):: Bool'或set [1,2,3] :: Maybe Int'這樣的問題? – leftaroundabout

+0

我認爲應該可以在編譯時用一個簡單的實例聲明替換聲明,所以類型系統應該保持不變,儘管我同意這個提議與Haskell的派生機制非常不相關;也許名稱變化是爲了。 – user1502040

+0

什麼聲明應該被什麼取代?你能舉一個你想如何使用它的例子嗎? – leftaroundabout

回答

4

你在這裏描述的基本上是通過同構定義類實例。這明顯可以通過定義getset函數來實現,但我們將其稱爲tofro,以便更清楚一點。

toSI :: String -> Integer 
fromSI :: Integer -> String 

instance Num String where 
    a + b = fromSI $ (toSI a) + (toSI b) 
    abs = fromSI . abs . toSI 
    ... 

這些確實是很容易的定義寫,有可能是通過在(to, fro)自動升降類的實例,這個系統必須認真遵循許多規則,爲了不污染全局類型類減少樣板一些價值實例空間與垃圾。

特別是,我們可能會問(to, fro)形成一個同構。這意味着在雙向往返是身份。換言之,這意味着給定任何整數n,我不應該能夠通過任何方式區分(froSI (toSI n))n(好吧,有些東西,比如計算速度會被忽略)。此外,我必須擁有的任何字符串stoSI (froSI s)必須與n無法區分。

第二個明顯失敗,因爲"I am not a number!"在該往返中拋出錯誤。有很多原因爲什麼在純代碼中拋出錯誤是危險的,而且類型類危險會繼續並污染任何曾經導入代碼的人的代碼。

您可能會指出,這只是因爲並非所有字符串都是有效數字。好像fromSI . toSI總是麻煩,但toSI . fromSI應該工作。也許它隻影響像例化instance Num String這樣的東西,而如果我們改爲使用我們的(toSI, froSI)對來推導instanceIntegerString我們會處於一個好位置。 也許吧。

讓我們試試吧。 StringMonoid一個實例,看起來像這樣

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 

這似乎應該工作得很好。它真的是IntegerInteger繼承其「單向同構」與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包定義之類的東西SumProduct這表明該Integer一直專注於只使用其Addition性能。

就是這樣,在一天結束時,您完全可以解決類型實例超出同構的問題。通常情況下,類型具有很多可以以這種方式濫用的同構和縮進,並且很難有真正的規範,守法的實例。當你找到一個代碼時,通常值得把代碼稅明確寫出來,即使你最終使用同構來完成。

當沒有你有一個像newtype文書規範的選擇和庫的快速訪問哪些只是「下面」你newtype層全部從普通GeneralizedNewtypeDeriving擴展出路的Control.Newtype package或直接啓發Iso, au and auf擺和整個Wrapped, ala, alaf機制lens

本質上,這個機制是爲了讓它更容易地討論各種同構,特別是那些由newtype誘發的實例。