Piszę aplikację podobną do CRUD i mam wiele wyszukiwań według klucza podstawowego (klucze podstawowe mogą mieć różne typy). Więc zdefiniowane następujące typeclass:Inferring Eq typeclass
{-# LANGUAGE MultiParamTypeClasses #-}
class Eq b => HasPK a b where
getPK :: a -> b
Teraz mogę napisać:
import Data.Maybe
lookupPK :: HasPK a b => b -> [a] -> Maybe a
lookupPK s = listToMaybe . filter ((== s) . getPK)
Teraz, gdy chcę porównać dwie rzeczy PK, po prostu chcę, aby porównać ich PK-tych. Więc staram się zdefiniować następująco:
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE UndecidableInstances #-}
instance (HasPK a b) => Eq a where
(==) = (==) `on` getPK
Ale teraz daje mi:
src/Utils.hs:61:10: Could not deduce (HasPK a b0) …
arising from the ambiguity check for an instance declaration
from the context (HasPK a b)
bound by an instance declaration: HasPK a b => Eq a
at /home/utdemir/workspace/.../Utils.hs:61:10-28
The type variable ‘b0’ is ambiguous
In the ambiguity check for: forall a b. HasPK a b => Eq a
To defer the ambiguity check to use sites, enable AllowAmbiguousTypes
In the instance declaration for ‘Eq a’
Compilation failed.
Może ktoś wyjaśnić ten błąd do mnie? Czy jestem na dobrej drodze, czy istnieje bezpieczniejszy sposób osiągnięcia tego, czego chcę?
Tak, po zdefiniowaniu tej instancji otrzymałem 'src/Utils.hs: 52: 20: nakładające się instancje dla Eq Integer wynikające z użycia '/ =' ... Przykłady dopasowania: instancja Eq Integer - Zdefiniowana w instancji 'integer-gmp: GHC.Integer.Type' (Eq b, HasPK a b) => Eq a'. Ale nie spodziewałem się tego błędu, ponieważ 'Integer' nie ma instancji' HasPk Integer b'. Zrozumiałbym błąd, jeśli zdefiniuję zarówno Eq, jak i HasPK, ale ponieważ nie ma "HasPK Integer", czy nie powinien on bezpośrednio używać zwykłej instancji 'Eq'? – utdemir
@utdemir Problem polega na tym, że 'instancja C a => Eq a' odnosi się do każdego typu, nawet do tych, dla których' C a' jest fałszywe (!). Haskell zobowiąże się do użycia tej instancji, a gdy "C a" to będzie błędne, zamiast wycofywać i szukać innych instancji. Dzieje się tak, ponieważ przy cofaniu problem staje się znacznie trudniejszy, a projektanci Haskella zajęli się czasem kompilacji.GHC ma rozszerzenie 'OverlappingInstances', które rozluźnia to ograniczenie, ale nie polecam go. Należy unikać nakładania się instancji, IMHO. – chi
Dziękuję, poszedłem z rozwiązaniem typu rodziny, ponieważ wygląda na to, że najmniej kontrowersyjne jest rozszerzenie. – utdemir