2016-01-13 34 views
1

我有以下代碼:無法理解,爲什麼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,這應該允許可摺疊的容器,但有問題的錯誤報文不會使對我來說任何意義。有人能澄清我在這裏沒有把握什麼嗎?

回答

3

您是否嘗試過實際實施該課程?看起來,默認定義和你的類型家族有一些奇怪之處。如果定義至少以下則文件類型檢查:

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 a0t == RuleSeta == a0。然後a ~ Element (RuleSet a),這是您的消息中的確切錯誤,將建議a ~ Rule a,這是不正確的。

+0

謝謝你 - 這個類型沒有描述'最小實現',我真的不確定實際需要或不需要。 另外,爲什麼你現在知道你永遠不會使用優雅的前奏?這可以在上游解決嗎? –

+1

@KozRoss我喜歡前奏中的一些權力,但最終的前奏應該是原則性的,而且很簡單。即使我們現在在GHC中使用了相當大的默認Prelude,其原理也很清晰,並沒有使用特別複雜的功能 - 種類,MPTC,TypeFamilies都在其他地方。它不依賴於大量的庫或大量的數據類型,某些作者可能認爲它應該是該語言的一部分。 –

+1

這是一個愚蠢的結論,因爲有可用的功能的默認實現。默認實現可用於解決多態容器(如列表和向量)的常見情況,並且需要重寫否則。我無法想出任何你認爲這不符合這種(非常標準)違約使用原則的設計。 –

3

爲了澄清有關默認的實現:因爲有大量的類型在那裏它們是正確的多態性 - 並因此Functor實例 - MonoFunctor提供了一種簡單的方法,使這些也MonoFunctor情況下,通過default method signatures。如果您有Functor,只需聲明instance MonoFunctor就足夠了。

對於您的情況,您會收到令人困惑的錯誤消息,因爲您的類型實際上是Functor,但是與您想要的MonoFunctor實例類型不同。具體而言,通過它的形狀,RuleSet a對於aFunctor,而您希望它是Rule a。這沒有什麼不對,它只是與默認實現衝突,因此您需要提供單獨的實現。

請注意,這不是特定於您的類型:任何不是從FunctorMonoFunctor的簡單翻譯都需要這項工作。這適用於一些內置實例,如TextByteString

相關問題