Zajmuję się wyspecjalizowaną biblioteką przetwarzania danych numerycznych i napotkałem błąd, którego nie potrafię rozwiązać. Myślę, że łatwiej będzie najpierw pokazać przykład, a potem wyjaśnić mój problem. Przepraszam również za dziwne nazwiska, które muszę zaciemnić dla celów prawnych.Rozwiązywanie niejednoznacznych wystąpień dla typu wielobajtowego klasy
{-# 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
Gdy próbuję skompilować ten, pojawia się błąd
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'
Ponieważ kompilator nie może dowiedzieć się, jakie konkretne wystąpienie MyNum
użyć do MyList
. Działa dla myAdd
, ponieważ typ zwrotny dla MyNum
jest łatwo wyprowadzony, ale nie może go znaleźć dla myLessThan
. Chcę użyć tej czcionki, aby móc łatwo dodać drobnoziarnistą obsługę błędów przez cały czas, a ponieważ mój aktualny kod ma odpowiednik +, -, *, /, <, < =,> i> = i chcę aby utworzyć instancję dla MyNum Double MyList MyList
, MyNum MyList MyList MyList
i podobne dla instancji NamedList
. O ile nie ma prostszego sposobu, aby to zrobić, to mogę mieć polimorficzne przemienne operatory.
Jednak nie mogę określić, jaki typ podpisu dodać do myLessThan
dla drugiej instancji, aby mógł wiedzieć, której instancji użyć. Wiem, że jednym z rozwiązań byłoby podzielenie operatorów arytmetycznych i porównawczych na dwie oddzielne klasy typów, ale chciałbym tego uniknąć, jeśli to w ogóle możliwe.
Jest to dla mnie wcześniej nieznany konstrukt w Haskell i dokładnie to, czego potrzebowałem, dzięki! – bheklilr
@bheklilr cieszę się, że mogę pomóc. Możesz również dowiedzieć się o TypeFamilies, które są łatwiejsze w obsłudze i na większą skalę. – jberryman