How to make ghc show me the result of applying a type family to a type

i have the following code

import Data.Kind(Type)
type ArrowMap::(Type->Type) -> Type-> Type 
type family ArrowMap f a where
  ArrowMap f (r -> b) = (f r -> ArrowMap f b)
  ArrowMap f a = f a
 
concatChar :: Char -> Char -> Char -> [Char]
concatChar a b c = [a,b,c]

class Applicable f a where
  applyN ::f a -> ArrowMap f a

instance (Applicative f, Applicable f a) => Applicable f (r ->  a)  where
  applyN f = applyN . (<*>) f
instance (ArrowMap f a ~ f a, Applicative f) => Applicable f a where
  applyN f = f
main :: IO () 
main = (applyN . pure $ concatChar) getChar getChar getChar >>= putStrLn 

i get the following error when compiling this

[1 of 2] Compiling Main             ( Main.hs, Main.o ) [Source file changed]

Main.hs:22:9: error:
    • Overlapping instances for Applicable
                                  IO (Char -> Char -> Char -> [Char])
        arising from a use of ‘applyN’
      Matching instances:
        instance (ArrowMap f a ~ f a, Applicative f) => Applicable f a
          -- Defined at Main.hs:19:10
        instance (Applicative f, Applicable f a) => Applicable f (r -> a)
          -- Defined at Main.hs:17:10
    • In the first argument of ‘(.)’, namely ‘applyN’
      In the first argument of ‘($)’, namely ‘applyN . pure’
      In the first argument of ‘(>>=)’, namely
        ‘(applyN . pure $ concatChar) getChar getChar getChar’
   |
22 | main = (applyN . pure $ concatChar) getChar getChar getChar >>= putStrLn 
   |  

if i then place a overlapping pragma on the first instance it compiles and runs as expected getting 3 characters and outputting them, crucially to solve this i need to know why ArrowMap f a is equal to f a, i suspect something involving the ((->) r) monad but can’t be sure.
i trieh to use :t ArrowMap functor type on ghci but it complained about illegal term level usage of a type family which makes sense as :t gets the type of an expression so hence my question

You can use :kind! or just :k! to evaluate type families, e.g.:

> data A
> data F a
> :kind! ApplyMap F A
ArrowMap F A :: *
 = F A

So ArrowMap f a = f a.

1 Like

thanks for the help. will add that if you use an explicit forall you can even use type variables. i still couldn’t solve why the instances overlap. using ArrowMap ((->) r) (a → c) shows exactly what i expected (r → a) → ArrowMap ((->) r) c which means it couldn’t possibly choose this instance. as (r → a) → ArrowMap ((->) r) c can never equal r → a → c. should i make another post about why the instances overlap or can the discussion continue in this one?

Oh, I think the overlap happens because GHC will first try to match the instance head, which does not include the constraints. If you only look at Applicable f (r -> a) and Applicable f a then it is clear that they overlap.

This behavior is documented in the user manual: 6.8.8. Instance declarations and resolution — Glasgow Haskell Compiler 9.4.1 User's Guide

You can see it in action if you remove the Applicable f (r -> a) instance. It will still resolve the Applicable constraint, but it will give you a type error:

• Couldn't match type: IO Char -> IO Char -> IO Char -> IO [Char]
                 with: IO (Char -> Char -> Char -> [Char])
    arising from a use of ‘applyN’