Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UndecidableInstances and newtypes

Tags:

haskell

I have an UndecidableInstances problem that I haven't been able to figure out how to avoid using newtype. Here's what I had originally:

{-# 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

The message I get is

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)'

I want to avoid UndecidableInstances because this code is going to be in a reusable library, so I try declaring a 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

But I get the same error. I've read answers to other questions on UndecidableInstances, but I haven't been able to solve this.

like image 956
mhwombat Avatar asked Apr 22 '14 10:04

mhwombat


1 Answers

As a horrible kludge, double-wrapping and using FlexibleInstances seem to do the trick:

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
like image 59
Cactus Avatar answered Sep 23 '22 18:09

Cactus