Не могу понять, почему MonoFoldable для моего типа не компилируется, или сообщение об ошибке
У меня есть следующий код:
{-# LANGUAGE NoImplicitPrelude, OverloadedStrings, TypeFamilies #-}
module AI.Analysis.Rules where
import ClassyPrelude
-- Our set of rules
data RuleSet a = RuleSet [Rule a] [Rule a]
deriving (Eq)
mkRuleSet :: (Ord a) => [Rule a] -> RuleSet a
mkRuleSet rules = uncurry RuleSet (partition isStandard uniques)
where uniques = ordNub rules
isStandard x = case x of
Standard _ _ -> True
LastResort _ -> False
instance (Show a) => Show (RuleSet a) where
show (RuleSet s l) = unlines [toLines s, "----", toLines l]
where toLines = unlines . fmap show
instance (Ord a) => Monoid (RuleSet a) where
mempty = RuleSet [] []
mappend (RuleSet s1 l1) (RuleSet s2 l2) = RuleSet (ordNub (s1 ++ s2)) (ordNub (l1 ++ l2))
instance (Ord a) => Semigroup (RuleSet a) where
(<>) = mappend
type instance Element (RuleSet a) = (Rule a)
instance MonoFoldable (RuleSet a) --this is unhappy
-- A rule in our system
-- For now, we assume rules *individually* are always internally-consistent
data Rule a = Standard [a] a | LastResort a
deriving (Eq)
mkRule :: (Eq a, Ord a) => [a] -> a -> Rule a
mkRule as c = case as of
[] -> LastResort c
_ -> Standard ((sort . ordNub) as) c
-- Last-resort rules and standard rules cannot be compared for consistency
mutuallyConsistent :: (Eq a) => Rule a -> Rule a -> Maybe Bool
mutuallyConsistent (LastResort c1) (LastResort c2) = Just (c1 == c2)
mutuallyConsistent (Standard as1 c1) (Standard as2 c2) = Just ((as1 /= as2) || (c1 == c2))
mutuallyConsistent _ _ = Nothing
instance (Show a) => Show (Rule a) where
show x = case x of
Standard as c -> formatAnd as ++ " -> " ++ show c
LastResort c -> "-> " ++ show c
where formatAnd = unwords . intersperse "^" . map show . otoList
-- LastResort rules are always ordered smaller than standard ones
instance (Ord a) => Ord (Rule a) where
(<=) (LastResort _) (Standard _ _) = True
(<=) (Standard _ _) (LastResort _) = False
(<=) (LastResort c1) (LastResort c2) = c1 <= c2
(<=) (Standard as1 c1) (Standard as2 c2) = (as1 <= as2) || (c1 <= c2)
Тем не менее, я получаю следующую ошибку от компилятора, смысл которой у меня возникли проблемы с пониманием:
/home/koz/documents/uni/research/summer-research-2015/clinical/rules-analysis/src/AI/Analysis/Rules.hs:47:10:
Couldn't match type ‘a’ with ‘Rule a’
‘a’ is a rigid type variable bound by
the instance declaration
at /home/koz/documents/uni/research/summer-research-2015/clinical/rules-analysis/src/AI/Analysis/Rules.hs:47:10
Expected type: Element (RuleSet a)
Actual type: a
Relevant bindings include
ofoldMap :: (Element (RuleSet a) -> m) -> RuleSet a -> m
(bound at /home/koz/documents/uni/research/summer-research-2015/clinical/rules-analysis/src/AI/Analysis/Rules.hs:47:10)
In the expression:
mono-traversable-0.10.0.1:Data.MonoTraversable.$gdmofoldMap
In an equation for ‘ofoldMap’:
ofoldMap
= mono-traversable-0.10.0.1:Data.MonoTraversable.$gdmofoldMap
In the instance declaration for ‘MonoFoldable (RuleSet a)’
Насколько я могу судить, мое мышление, кажется, имеет смысл - в конце концов, RuleSet
это просто контейнер для Rule
s, что должно учитывать возможность складывания, но рассматриваемое сообщение об ошибке не имеет для меня никакого смысла. Может кто-нибудь уточнить, что я здесь не понял?
2 ответа
Вы действительно пытались реализовать класс? Кажется, есть некоторая странность с определениями по умолчанию и вашим семейством типов. Если вы укажете хотя бы нижеприведенное, тогда тип файла проверяется:
instance MonoFoldable (RuleSet a) where --this is unhappy
ofoldl1Ex' = undefined
ofoldr1Ex = undefined
ofoldl' = undefined
ofoldr = undefined
ofoldMap = undefined
РЕДАКТИРОВАТЬ: классная прелюдия, которую я теперь знаю, я никогда не буду использовать, имеет реализации по умолчанию и сигнатуры типов, которые включают в себя ограничения t a ~ mono, a ~ Element (t a)
, Работать осторожно, так как мне пришлось дважды подумать здесь. t a ~ RuleSet a0
так t == RuleSet
а также a == a0
, затем a ~ Element (RuleSet a)
, которая является вашей точной ошибкой в сообщении, предложит a ~ Rule a
и это просто не правильно.
Чтобы уточнить о реализациях по умолчанию: так как существует большое количество типов, которые являются должным образом полиморфными - и, следовательно, экземпляры Functor
- MonoFunctor
обеспечивает простой способ сделать эти также случаи MonoFunctor
, через подписи метода по умолчанию. В случае, если у вас есть Functor
, просто заявив instance MonoFunctor
достаточно.
В вашем случае вы получаете сообщение об ошибке, так как ваш тип Functor
, но для другого типа, чем вы хотели MonoFunctor
пример. В частности, по своей форме, RuleSet a
это Functor
за a
пока ты хочешь чтобы это было Rule a
, В этом нет ничего плохого, он просто конфликтует с реализациями по умолчанию, и поэтому вам нужно предоставить отдельные реализации.
Обратите внимание, что это не относится к вашему типу: все, что не является простым переводом с Functor
в MonoFunctor
требует этой работы. Это относится к некоторым встроенным экземплярам, таким как Text
а также ByteString
,