2013-04-04 76 views
8

假設我有以下類:哈斯克爾繼承類型類

class P a where 
    nameOf :: a -> String 

我想聲明的是這個類的所有實例都自動的Show實例。我第一次嘗試將是如下:

instance P a => Show a where 
    show = nameOf 

我第一次走這條路昨天導致語言擴展的養兔場的嘗試:我是第一次告知要靈活的情況下切換,那麼不可判定的情況下,則可以重疊的情況下,最後得到一個關於重疊實例聲明的錯誤。我放棄了,然後回到重複的代碼。然而,這從根本上看似乎是一個非常簡單的需求,而且應該很容易滿足。

於是,兩個問題:

  1. 有一個平凡簡單的方法來做到這一點,我剛剛錯過?
  2. 爲什麼我會遇到重疊實例問題?我可以明白爲什麼我可能需要UndecidableInstances,因爲我似乎違反了Paterson條件,但是在這裏沒有重疊的情況:甚至沒有P的實例。爲什麼typechecker認爲有多個實例Show Double(在這個玩具的例子中似乎是這種情況)?
+3

重疊(和重載分辨率)僅由實例頭部'Show a'確定,所以它確實與其他每個Show實例重疊。 – augustss 2013-04-04 10:03:23

+1

假設你聲明瞭'P Int'的實例,並且你已經有了'Show Int'的實例,所以這將導致Show的重疊實例。 – Satvik 2013-04-04 10:06:09

+0

@Satvik當然,除了我沒有'P Int'的實例。如果我試圖創建一個'P Int',我會期待一個錯誤,但不是僅僅聲明它可能存在。 – Impredicative 2013-04-04 10:14:13

回答

5

你得到重疊的情況下錯誤,因爲你的一些的P實例可能有Show其他實例,那麼編譯器將無法決定使用哪一個。如果你的P的實例爲Double,那麼你去了,你得到Show的兩個實例Double:你的一般和已經在Haskell的基礎庫中聲明的實例。 @augustss在你的問題的評論中正確地陳述了這個錯誤是如何被觸發的。欲瞭解更多信息,請登錄the specs

正如你所知,沒有UndecidableInstances沒有辦法實現你正在嘗試的東西。當您啓用該標誌時,您必須明白您正在接管編譯器的責任,以確保不會出現任何衝突的實例。這意味着,當然,在您的圖書館中不得存在任何其他Show實例。這也意味着您的庫不會導出P類,這將消除庫的用戶聲明衝突實例的可能性。

如果你的情況與上述說法有衝突,這是一個可靠的跡象,說明它一定有什麼問題。而事實上有...


你想達到什麼是不正確的首先。這是因爲丟失了幾個重要點有關Show類型類,從結構像一個toString方法流行的面嚮對象語言的區分是:

  1. Show's haddock

    顯示的結果是一個語法正確Haskell的表達只包含常量,因爲在聲明類型的地方有效的固定性聲明。它僅包含數據類型,括號和空格中定義的構造函數名稱。使用帶標籤的構造函數字段時,還使用大括號,逗號,字段名稱和等號。

    換句話說,聲明不產生有效Haskell表達式的Show的實例本身是不正確的。

  2. 鑑於上述情況,只有在類型允許簡單派生它時聲明Show的自定義實例纔沒有意義。

  3. 當一個類型不允許導出它(例如,GADT),通常你還是要堅持鍵入特定的情況下,產生正確的結果。

因此,如果您需要自定義表示功能,則不應使用Show。只需聲明自定義類,例如:

class Repr a where 
    repr :: a -> String 

並且負責任地處理實例聲明。

+0

我很謹慎接受這個答案,因爲我覺得這在技術上部分是錯誤的。問題不在於'P'的某些實例有'Show'的其他實例:如上所述,*有*沒有'P'的實例。 「augustss」已經解釋了真正的問題,即如何評估重疊。如果你解決了這個問題,我很樂意接受。我對你使用'show'的觀點有所瞭解。 – Impredicative 2013-04-04 15:44:55

+0

@Impredicative可能我沒有說清楚,我已經更新了第一段。 – 2013-04-04 16:07:42