简体   繁体   中英

Instances for SingI class from import GHC.TypeLits

toying around with GHC.TypeLits I made this code

data A (a :: Symbol) = A
type B a (b :: Symbol) (c :: Symbol) = A a

class AC a where
  af :: (String, a)

-- instance SingI a => AC (A a) where
--   af = (fromSing (sing :: Sing a), A)

instance (SingI a, SingI b, SingI c) => AC (B a b c) where
  af = (fromSing (sing :: Sing c), A)

Which fails to compile if I try to call af somewhere with this error:

No instance for (SingI Symbol c) arising from a use of `af'
Possible fix: add an instance declaration for (SingI Symbol c)
In the second argument of `($)', namely
  `(af :: (String, B "a" "b" "c"))'
In the second argument of `($)', namely
  `fst $ (af :: (String, B "a" "b" "c"))'
In a stmt of a 'do' block:
  print $ fst $ (af :: (String, B "a" "b" "c")) 

Still it works fine for instance SingI a => AC (A a) it's clear that it's something with type synonym, but I can't find any explanation of this. Would be glad to hear why it works like this, and is there any chance to add some king of tag to type synonym?

Extension, used to compile:

  DataKinds,
  KindSignatures,
  TypeSynonymInstances,
  ScopedTypeVariables,
  -- MultiParamTypeClasses,
  UndecidableInstances

From the GHC User Guide, section 7.6.3.1. Relaxed rules for the instance head :

With the -XTypeSynonymInstances flag, instance heads may use type synonyms. As always, using a type synonym is just shorthand for writing the RHS of the type synonym definition.

Applying this rule to your instance declaration leads to:

instance (SingI a, SingI b, SingI c) => AC (A a) where
  af = (fromSing (sing :: Sing c), A)

Note that this is equal to the instance you wrote for 'A', but with constraints on c and b , which now don't even appear in the instance head. When you try to use the instance:

print $ fst $ (af :: (String, B "a" "b" "c")) 

That gets transformed to

print $ fst $ (af :: (String, A "a"))

And the compiler complains that there is no instance for SingI Symbol c , because it doesn't know what c is. To make this code compile, you'd have to provide an instance SingI (c :: Symbol) that works for all c (you can write such an instance with FlexibleInstances , but it's not going to be useful because you can't make a choice depending on c ). If you don't want this behaviour, you could use a newtype.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM