Не могу понять, почему 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 это просто контейнер для Rules, что должно учитывать возможность складывания, но рассматриваемое сообщение об ошибке не имеет для меня никакого смысла. Может кто-нибудь уточнить, что я здесь не понял?

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,

Другие вопросы по тегам