[Haskell-cafe] ambiguous type variable question

Zoran Bošnjak zoran.bosnjak at via.si
Wed Oct 11 10:23:31 UTC 2023


I am including the instances. The error is:

    • Couldn't match expected type: SchemaVal G1
                  with actual type: SchemaVal G2
      NB: ‘SchemaVal’ is a non-injective type family
      The type variables ‘b3’, ‘b2’ are ambiguous
    • In the second argument of ‘(/=)’, namely ‘schema @G2’
      In the first argument of ‘print’, namely
        ‘(schema @G1 /= schema @G2)’
      In a stmt of a 'do' block: print (schema @G1 /= schema @G2)

{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}

module Test where

import Data.Kind
import Data.Proxy
import GHC.TypeLits

data Content n s b
  = ContentRaw
  | ContentTable [(n, s)]
  | ContentBool b

deriving instance (Show n, Show s, Show b) => Show (Content n s b)

data Variation n s b
  = Element n (Content n s b)
  | Group [Item n s b]

deriving instance (Show n, Show s, Show b) => Show (Variation n s b)

data Item n s b
  = Spare n
  | Item s (Variation n s b)

deriving instance (Show n, Show s, Show b) => Show (Item n s b)

-- Convert from types to values.
class IsSchema t where
  type SchemaVal t :: Type
  schema :: SchemaVal t

instance IsSchema 'ContentRaw where
  type SchemaVal ContentRaw = Content Integer String Bool
  schema = ContentRaw

instance IsSchema ('ContentTable '[]) where
  type SchemaVal (ContentTable '[]) = Content Integer String Bool
  schema = ContentTable []

instance
  ( IsSchema ('ContentTable ts :: Content Nat Symbol Bool)
  , t ~ '(n, s)
  , KnownNat n
  , KnownSymbol s
  , SchemaVal ('ContentTable ts :: Content Nat Symbol Bool) ~ Content Integer String Bool
  )
  => IsSchema ('ContentTable (t ': ts))
  where
  type SchemaVal ('ContentTable (t ': ts)) = Content Integer String Bool
  schema = case schema @('ContentTable ts :: Content Nat Symbol Bool) of
    ContentTable lst ->
      let n = natVal (Proxy @n)
          s = symbolVal (Proxy @s)
       in ContentTable ((n, s) : lst)
    _ -> error "internal error"

instance IsSchema 'True where
  type SchemaVal 'True = Bool
  schema = True

instance IsSchema 'False where
  type SchemaVal 'False = Bool
  schema = False

instance
  ( IsSchema b
  , SchemaVal b ~ Bool
  )
  => IsSchema ('ContentBool b)
  where
  type SchemaVal ('ContentBool b) = Content Integer String Bool
  schema = ContentBool (schema @b)

instance
  ( KnownNat n
  , SchemaVal c ~ Content Integer String Bool
  , IsSchema c
  )
  => IsSchema ('Element n c)
  where
  type SchemaVal ('Element n c) = Variation Integer String Bool
  schema = Element (natVal (Proxy @n)) (schema @c)

instance IsSchema ('Group '[]) where
  type SchemaVal ('Group '[]) = Variation Integer String Bool
  schema = Group []

instance
  ( IsSchema t
  , IsSchema ('Group ts)
  , SchemaVal t ~ Item Integer String Bool
  , SchemaVal ('Group ts :: Variation Nat Symbol Bool) ~ Variation Integer String Bool
  )
  => IsSchema ('Group (t ': ts))
  where
  type SchemaVal ('Group (t ': ts)) = Variation Integer String Bool
  schema = case schema @('Group ts) of
    Group lst -> Group (schema @t : lst)
    _ -> error "internal error"

instance (KnownNat n) => IsSchema ('Spare n) where
  type SchemaVal ('Spare n) = Item Integer String Bool
  schema = Spare (natVal $ Proxy @n)

instance
  ( KnownSymbol s
  , IsSchema v
  , SchemaVal v ~ Variation Integer String Bool
  )
  => IsSchema ('Item s v)
  where
  type SchemaVal ('Item s v) = Item Integer String Bool
  schema = Item (symbolVal $ Proxy @s) (schema @v)

-- Test
type C = 'ContentRaw
type V1 = 'Element 1 C
type I1 = 'Item "title1" V1
type I2 = 'Item "title2" V1

type G0 = 'Group '[]
type G1 = 'Group (I1 ': '[])
type G2 = 'Group (I1 ': I2 ': '[])

main :: IO ()
main = do
  print $ schema @C
  print $ schema @('ContentBool 'True)
  print $ schema @V1
  print $ schema @I1
  print $ schema @I2
  print $ schema @G0
  print $ schema @G1
  print $ schema @G2
  print (schema @G1 /= schema @G2)


More information about the Haskell-Cafe mailing list