2014-04-22 2 views
7

Ich habe ein UndecidableInstances Problem, das ich nicht in der Lage gewesen bin, herauszufinden, wie man newtype vermeiden kann. Hier ist, was ich hatte ursprünglich:UndecidableInstances und newtypes

{-# LANGUAGE TypeFamilies, FlexibleContexts #-} 

class Record r where 
    key :: r -> String 

class (Record r) => SizedRecord r where 
    size :: r -> Int 

class Database d where 
    type DBRecord d 

class (Record a) => Agent a where 
    agentId :: a -> String 
    agentId = key 

class (Database (UAgentDB u), Agent (UAgent u), Record (UAgent u)) 
     => Universe u where 
    type UAgent u 
    type UAgentDB u 
    -- plus other stuff 

data SimpleUniverse d = SimpleUniverse 
    { 
    suDB :: d 
    -- plus other stuff 
    } deriving (Show, Eq) 

instance (Record (DBRecord d)) => Universe (SimpleUniverse d) where -- line 28 
    type UAgent (SimpleUniverse d) = DBRecord d 
    type UAgentDB (SimpleUniverse d) = d 
    -- plus other stuff 

Die Botschaft, die ich erhalte, ist

amy9.hs:28:10: 
    Constraint is no smaller than the instance head 
     in the constraint: Record (DBRecord d) 
    (Use -XUndecidableInstances to permit this) 
    In the instance declaration for `Universe (SimpleUniverse d)' 

ich UndecidableInstances vermeiden will, weil dieser Code in einer wiederverwendbaren Bibliothek sein wird, so dass ich versuchen zu erklären ein newtype:

newtype SimpleUniverse2 u = SimpleUniverse2 { fromAdditiveGroup :: u } 

instance (Record (DBRecord u)) => Universe (SimpleUniverse2 u) where 
    type UAgent (SimpleUniverse2 u) = DBRecord u 
    type UAgentDB (SimpleUniverse2 u) = u 
    -- plus other stuff 

Aber ich bekomme den gleichen Fehler. Ich habe Antworten auf andere Fragen auf UndecidableInstances gelesen, aber ich konnte das nicht lösen.

+0

Warum genau wollen Sie nicht 'UndecidableInstances'? Daran ist nicht viel Schlechtes. – leftaroundabout

+0

Wenn es hier in Ordnung ist, ist das großartig. Ich dachte nur, ich sollte es vermeiden wegen solcher Beiträge: https://lukepalmer.wordpress.com/2008/04/08/stop-using-undecidable-instances/ – mhwombat

+1

Es ist völlig ok hier, solange du nicht willst Beginnen Sie mit der Definition von 'Record'-Instanzen basierend auf einigen 'Universe'. – leftaroundabout

Antwort

1

Als schreckliche Flickschusterei, Doppel-Verpackung und mit FlexibleInstances scheinen den Trick zu tun:

import Control.Monad.Identity  

instance (Database u, Agent (DBRecord u), Record (DBRecord u)) => 
     Universe (Identity (Identity u)) where 
    type UAgent (Identity (Identity u)) = DBRecord u 
    type UAgentDB (Identity (Identity u)) = u