Skip to content

GHC unexpectedly reports variable as untouchable and suggests -XAmbiguousTypes after enabling constraints via associated type family under rank2 argument

Sorry for long subject, couldn't express it in a more succinct way :)

Please consider the following program. I have defined function hzygo without any issues, but after slight generalisation GHC doesn't accept hzygo1 any more. Please see the error message below the program. However, slightly more general hzygo2 is accepted.

{-# LANGUAGE ConstraintKinds     #-}
{-# LANGUAGE DataKinds           #-}
{-# LANGUAGE GADTs               #-}
{-# LANGUAGE KindSignatures      #-}
{-# LANGUAGE NoStarIsType        #-}
{-# LANGUAGE PolyKinds           #-}
{-# LANGUAGE RankNTypes          #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies        #-}

module Main (main) where

import Data.Kind
import Data.Functor.Product

hfst :: Product a b ix -> a ix
hfst (Pair a _) = a

hsnd :: Product a b ix -> b ix
hsnd (Pair _ b) = b

newtype HFix (f :: (k -> Type) -> (k -> Type)) (ix :: k) =
  HFix { unHFix :: f (HFix f) ix }


class HFunctor (f :: (k -> Type) -> (k -> Type)) where
  hmap :: (forall ix. a ix -> b ix) -> (forall ix. f a ix -> f b ix)

hcata
  :: forall f a.
     HFunctor f
  => (forall ix. f a ix -> a ix)
  -> (forall ix. HFix f ix -> a ix)
hcata alg = go
  where
    go :: forall ix. HFix f ix -> a ix
    go = alg . hmap go . unHFix

hzygo
  :: forall f a b.
     HFunctor f
  => (forall ix. f (Product a b) ix -> a ix)
  -> (forall ix. f b ix             -> b ix)
  -> (forall ix. HFix f ix          -> a ix)
hzygo alga algb = hfst . hcata alg
  where
    alg :: f (Product a b) ix -> Product a b ix
    alg x = Pair (alga x) (algb $ hmap hsnd x)

class Constrained (f :: (k1 -> k2) -> (k1 -> k2)) where
  type Constraints f :: k1 -> Constraint

class Constrained f => HFunctor' (f :: (k -> Type) -> (k -> Type)) where
  hmap'
    :: (forall ix. Constraints f ix => a ix -> b ix)
    -> (forall ix. Constraints f ix => f a ix -> f b ix)

hcata'
  :: forall f a.
     HFunctor' f
  => (forall ix. Constraints f ix => f a ix -> a ix)
  -> (forall ix. Constraints f ix => HFix f ix -> a ix)
hcata' alg = go
  where
    go :: forall ix. Constraints f ix => HFix f ix -> a ix
    go = alg . hmap' go . unHFix

hzygo2
  :: forall f a b.
     HFunctor' f
  => (forall ix. Constraints f ix => f (Product a b) ix -> a ix)
  -> (forall ix. Constraints f ix => f b ix             -> b ix)
  -> (forall ix. Constraints f ix => HFix f ix          -> Product a b ix)
hzygo2 alga algb = hcata' alg
  where
    alg :: Constraints f ix => f (Product a b) ix -> Product a b ix
    alg x = Pair (alga x) (algb $ hmap' hsnd x)

hzygo1
  :: forall f a b.
     HFunctor' f
  => (forall ix. Constraints f ix => f (Product a b) ix -> a ix)
  -> (forall ix. Constraints f ix => f b ix             -> b ix)
  -> (forall ix. Constraints f ix => HFix f ix          -> a ix)
hzygo1 alga algb = hfst . hcata' alg
  where
    alg :: Constraints f ix => f (Product a b) ix -> Product a b ix
    alg x = Pair (alga x) (algb $ hmap' hsnd x)


main :: IO ()
main =
  pure ()
$ ghc --version
The Glorious Glasgow Haskell Compilation System, version 8.6.5
$ ghc -c Main.hs

Main.hs:77:6: error:
    • Couldn't match type ‘b0’ with ‘b’
        ‘b0’ is untouchable
          inside the constraints: Constraints f ix1
          bound by the type signature for:
                     hzygo' :: forall (ix1 :: k1).
                               Constraints f ix1 =>
                               f b0 ix1 -> b0 ix1
          at Main.hs:(77,6)-(81,64)
      ‘b’ is a rigid type variable bound by
        the type signature for:
          hzygo' :: forall k1 (f :: (k1 -> *) -> k1 -> *) (a :: k1
                                                                -> *) (b :: k1 -> *).
                    HFunctor f =>
                    (forall (ix1 :: k1).
                     Constraints f ix1 =>
                     f (Product a b) ix1 -> a ix1)
                    -> (forall (ix1 :: k1). Constraints f ix1 => f b ix1 -> b ix1)
                    -> forall (ix :: k1). Constraints f ix => HFix f ix -> a ix
        at Main.hs:(77,6)-(81,64)
      Expected type: f b0 ix1 -> b0 ix1
        Actual type: f b ix1 -> b ix1
    • In the ambiguity check for ‘hzygo'’
      To defer the ambiguity check to use sites, enable AllowAmbiguousTypes
      In the type signature:
        hzygo' :: forall f a b.
                  HFunctor f =>
                  (forall ix. Constraints f ix => f (Product a b) ix -> a ix)
                  -> (forall ix. Constraints f ix => f b ix -> b ix)
                     -> (forall ix. Constraints f ix => HFix f ix -> a ix)
   |
77 |   :: forall f a b.
   |      ^^^^^^^^^^^^^...

Main.hs:77:6: error:
    • Couldn't match type ‘b0’ with ‘b’
        ‘b0’ is untouchable
          inside the constraints: Constraints f ix1
          bound by the type signature for:
                     hzygo' :: forall (ix1 :: k1).
                               Constraints f ix1 =>
                               f (Product a b0) ix1 -> a ix1
          at Main.hs:(77,6)-(81,64)
      ‘b’ is a rigid type variable bound by
        the type signature for:
          hzygo' :: forall k1 (f :: (k1 -> *) -> k1 -> *) (a :: k1
                                                                -> *) (b :: k1 -> *).
                    HFunctor f =>
                    (forall (ix1 :: k1).
                     Constraints f ix1 =>
                     f (Product a b) ix1 -> a ix1)
                    -> (forall (ix1 :: k1). Constraints f ix1 => f b ix1 -> b ix1)
                    -> forall (ix :: k1). Constraints f ix => HFix f ix -> a ix
        at Main.hs:(77,6)-(81,64)
      Expected type: f (Product a b0) ix1 -> a ix1
        Actual type: f (Product a b) ix1 -> a ix1
    • In the ambiguity check for ‘hzygo'’
      To defer the ambiguity check to use sites, enable AllowAmbiguousTypes
      In the type signature:
        hzygo' :: forall f a b.
                  HFunctor f =>
                  (forall ix. Constraints f ix => f (Product a b) ix -> a ix)
                  -> (forall ix. Constraints f ix => f b ix -> b ix)
                     -> (forall ix. Constraints f ix => HFix f ix -> a ix)
   |
77 |   :: forall f a b.
   |      ^^^^^^^^^^^^^...
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information