2012-03-03 132 views
6

我試圖以歸納方式定義一對類實例。即:Haskell「不」類型約束

class Foo a b | a -> b where 
    foo :: a -> b 

instance (not?)Foo a => Bar a b 
    foo x = ... 

instance Foo a => Bar a b 
    foo x = ... 

第一個實例確定基本動作,秒遞歸調用foo。有沒有辦法做到這一點?一個很好的例子是扁平化一個列表,第一個例子是身份函數,第二個例子是concat的遞歸應用程序。

+10

請注意,在Haskell中,不可能確定給定類型是* not *給定類型類的實例,因爲其他人可以使用他們自己的代碼編譯您的代碼來提供實例。 – 2012-03-04 01:41:17

回答

5

這是一個implementation of a flatten function,適用於任何級別的嵌套列表。我不會真的推薦使用它 - 這裏只是爲了演示如何在Haskell中實現類似的功能。

+5

使用IncoherentInstances是一個麻煩的邀請。 – augustss 2012-03-04 02:08:18

+1

@augustss,非常真實,因此我放在榜首。不過,我認爲沒有'IncoherentInstances'就可以實現'flatten'(這可能是一個很好的表明,設計一個依賴這個函數的程序是一個壞主意)。 – 2012-03-04 05:02:02

+1

@ is7s:那裏的解決方案不能派生出扁平列表的類型(所以你必須指定它爲'flatten [[3],[4]] :: [Int]'。對於這個工作,你需要但是這可能是一個值得權衡的方法 – 2012-03-04 06:34:25

8

由於一個非常簡單的原因,沒有辦法直接進行此操作 - 實例選擇僅查看「頭」,即=>之後的部分。在上下文中沒有任何內容--之前的部分 - 可以影響選擇哪個實例。

對於簡單情況,您通常可以完全避免此問題,例如,如果數量有限的「基本情況」類型。一個常見的例子就是類型級別列表,其中有Cons的遞歸情況和Nil的基本情況,就是這樣。

在一般情況下,您通常需要某種「條件測試」類型的類,根據是否滿足某些條件來選擇類型,然後將實際實現切換到一個「幫助器」類,條件結果值作爲參數並用它來選擇一個實例。

+1

那你如何實現一個通用列表展平類成員呢? – Jonathan 2012-03-03 23:59:51

+7

那麼,最誠實的答案是,我不會。在我看來,如果沒有打破多態輸入,沒有辦法做到這一點,並沒有足夠的證明這個麻煩。這就是說,爲了扁平化列表,我認爲你可以依靠重疊的實例來選擇遞歸還是基本的情況。你在這裏使用'OverlappingInstances'嗎?你可能會需要這種或那種方式。 – 2012-03-04 00:02:11

+3

爲什麼你想要一個通用列表展平功能?這很少有用。 – augustss 2012-03-04 02:09:53