我正在開發一個專門的數值數據處理庫,並且遇到了一個我無法弄清楚如何解決的錯誤。我認爲首先展示一個例子並解釋我的問題會更容易。我也爲奇怪的名字表示歉意,爲了合法目的我不得不混淆視聽。解決多參數類型類的模糊實例
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}
data MyError = MyError String deriving (Eq, Show)
data MyList = MyList [Double] deriving (Eq, Show)
data NamedList = NamedList String MyList deriving (Eq, Show)
class MyNum a b ret where
myAdd :: a -> b -> Either MyError ret
myLessThan :: a -> b -> Either MyError Bool
instance MyNum MyList Double MyList where
myAdd (MyList xs) x = Right $ MyList $ map (+x) xs
myLessThan (MyList xs) x = Right $ all (< x) xs
instance MyNum NamedList Double NamedList where
myAdd (NamedList n l) x = fmap (NamedList n) $ myAdd l x
myLessThan (NamedList n l) x = myLessThan l x
如果我嘗試編譯,我得到了錯誤
No instance for (MyNum MyList Double ret0)
arising from a use of `myLessThan'
The type variable `ret0' is ambiguous
Possible fix: add a type signature that fixes these type variable(s)
Note: there is a potential instance available:
instance MyNum MyList Double MyList
-- Defined at testing_instances.hs:13:10
Possible fix:
add an instance declaration for (MyNum MyList Double ret0)
In the expression: myLessThan l x
In an equation for `myLessThan':
myLessThan (NamedList n l) x = myLessThan l x
In the instance declaration for `MyNum NamedList Double NamedList'
因爲編譯器無法弄清楚用於MyList
其中MyNum
具體實例。它適用於myAdd
,因爲MyNum
的返回類型很容易推導出來,但無法找出myLessThan
。我想使用這個類型類型,以便我可以輕鬆地添加細粒度的錯誤處理,並且因爲我的實際代碼具有等效於+, - ,*,/,<,< =,>和> =,我想要爲MyNum Double MyList MyList
,MyNum MyList MyList MyList
和NamedList
做出類似的實例。除非有更簡單的方法來做到這一點,否則我可以擁有多態交換操作符。
但是,我不知道什麼類型的簽名添加到第二個實例myLessThan
,以便它可以知道使用哪個實例。我知道一種解決方案是將算術和比較運算符分爲兩個單獨的類型類,但是我想盡可能避免這樣做。
這是Haskell以前對我而言不熟悉的構造,正是我所需要的,謝謝! – bheklilr
@bheklilr很高興我能幫到你。您可能還想了解TypeFamilies,它們在某些方面更易於使用,功能更強大。 – jberryman