2017-06-16 66 views
2

我定義了一個簡單的列表類型:「實例」的具體類型而不是typeclass?

data MyList a = End 
       |Entry a (MyList a) 

而不是deriving (Show)我實現明確自己所有MyList a其中aShow一個實例。

instance Show a => Show (MyList a) 
    where show End = "" 
     show (Entry a l) = (show a) ++","++(show l) 

這工作得很好。現在我想改變這種只有MyList StringShow一個實例,並且這樣做,我寫

instance Show (MyList String) 
    where show End = "" 
     show (Entry a l) = a ++","++(show l) 

,但是這導致的錯誤,我不明白:

Illegal instance declaration for `Show (MyList String)' 
    (All instance types must be of the form (T a1 ... an) 
    where a1 ... an are *distinct type variables*, 
    and each type variable appears at most once in the instance head. 
    Use FlexibleInstances if you want to disable this.) 
In the instance declaration for `Show (MyList String)' 

人解釋爲什麼這不起作用,這個錯誤告訴我什麼?

回答

3

錯誤是告訴你,標準的Haskell不允許這種類型的實例定義。正是因爲它說,

All instance types must be of the form (T a1 ... an) 
where a1 ... an are *distinct type variables*, 
and each type variable appears at most once in the instance head. 

其中一個原因是,如果你離開的您的實例定義,編譯器將不知道選擇哪一個MyList String,因爲它們都匹配。 (您可能還想看看rules for overlapping instances。)

在實例類型的形式上有這個約束可以保證類型檢查總是會終止的,雖然當然有有效的類型檢查程序,但實例不是這種形式,這就是它的工作原理:Haskell中的一些限制是保守的。

在你的特定情況下,只要做了編譯器的建議(即啓用FlexibleInstances)就可以做到這一點,而且這種擴展在終止方面是安全的。

+0

因此,如果不啓用'FlexibleInstances',我只能爲整個類型類指示'show',但不能指定特定類型? – flawr

+0

對於一個類型構造函數(例如你的'MyList :: * - > *'),你只能對類MyList a''的整個「類型族」一次性實現類(例如'Show')特定的個人喜歡'MyList String'或'MyList Bool'。 – kirelagin

+0

順便說一下,這就是爲什麼'Show'具有hacky ['showList']的原因(https://hackage.haskell.org/package/base-4.9.1.0/docs/Prelude.html#v:showList ) 方法。你想顯示不同於所有其他類型列表的'Char'列表,但是你不能在標準Haskell中單獨實現一個單獨的'Show [Char]'實例。 – kirelagin

相關問題