您可以採取幾種方法;我認爲你沒有提供足夠的背景來確定哪一個最合適。如果您使用GHC-7.4,則可能需要嘗試DefaultSignatures
擴展。
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE DefaultSignatures #-}
-- A generic class with a generic function.
class Foo a where
foo :: a -> a
default foo :: Bar a => a -> a
foo = bar . baz
-- A specific class with specific functions.
class Bar a where
bar :: a -> a
baz :: a -> a
instance Bar String where
bar = id
baz = id
instance Foo String
main :: IO()
main =
putStrLn (foo "bar")
你仍然需要聲明一個類型是Foo
一個實例,但你並不需要重複方法聲明,因爲默認的實現將被使用。
另一個相當輕量級的方法是使用新類型。如果您有需要Foo
實例的功能,則可以將新實例換成Bar
實例。
newtype FooBar a = FooBar { unFooBar :: a }
instance Bar a => Foo (FooBar a) where
foo = FooBar . bar . baz . unFooBar
-- imported from a library or something...
needsFoo :: Foo a => a -> b
myFunc = needsFoo (FooBar someBar)
或者,你可以用一個正常的功能替換foo
,或進行專門的版本,以獲得由Bar
實例:
-- if every `Foo` is also a `Bar`, you can just do this. No need for `Foo` at all!
foo :: Bar a => a -> a
foo = bar . baz
-- if most `Foo`s aren't `Bar`s, you may be able to use this function when you have a `Bar`
fooBar :: Bar a => a -> a
foo = bar . baz
這可能是最好的解決方案,如果他們的工作你的情況。
另一種選擇是手動聲明每個Foo
實例。雖然可能有很多不同的可能的例子,但是代碼庫通常只有少數實際使用的實例。如果這是真的,那麼僅僅寫出你需要的3或4個實例可能會少一些工作,而不是試圖實現更通用的解決方案。
作爲最後一招,您可以使用類似於您的原始代碼的東西,但您還需要OverlappingInstances
才能使其工作(如果您不需要OverlappingInstances
,則不需要Foo
類)。這是允許GHC在有多個可用匹配時選擇「最具體實例」的擴展。這或多或少的工作,雖然你可能得不到你所期望的。
class Foo a where
foo :: a -> a
class Bar a where
bar :: a -> a
baz :: a -> a
instance Bar String where
bar = id
baz = id
instance Bar a => Foo a where
foo = bar . baz
instance Foo [a] where
foo _ = []
main :: IO()
main =
print (foo "foo")
現在main
打印一個空字符串。有兩個Foo
實例,分別爲a
和[a]
。後者更具體,所以它被選爲foo "foo"
,因爲字符串的類型爲[Char]
,儘管您可能想要前者。所以,現在你也需要寫
instance Foo String where
foo = bar . baz
此時你不妨離開了Bar a => Foo a
實例完全。
通過聲明'實例Bar a => Foo a',您爲每個'a'引入了一個實例 - 上下文Bar a沒有用於實例選擇 - 但是如果您有重疊的實例,GHC將會找到最多在每個模塊的基礎上具體的一個。 – 2012-07-29 06:42:13
這是...反直覺:-)有沒有辦法解決它?我認爲「找到最具體的實例」就是「UndecidableInstances」將會嘗試做的事情,但在我的代碼中,它失敗了。 – 2012-07-29 07:33:12
相關:http://stackoverflow.com/questions/3213490 – sdcvvc 2012-07-29 09:40:38