Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Type abstraction in GHC Haskell

I'd love to get the following example to type-check:

{-# LANGUAGE AllowAmbiguousTypes    #-}
{-# LANGUAGE RankNTypes             #-}
{-# LANGUAGE TypeApplications       #-}
{-# LANGUAGE TypeFamilies           #-}

module Foo where

f :: Int -> (forall f. Functor f => Secret f) -> Int
f x _ = x

g :: (forall f. Functor f => Secret f) -> Int
g = f 4

type family Secret (f :: * -> *) :: * where
  Secret f = Int

I get it that it's probably not possible to infer and check gs type (even though in this specific case it's obvious because it's just a partial application): Secret is not injective and there's no way to tell the compiler which Functor instance it should expect. Consequently, it fails with the following error message:

    • Could not deduce (Functor f0)
      from the context: Functor f
        bound by a type expected by the context:
                  forall (f :: * -> *). Functor f => Secret f
        at src/Datafix/Description.hs:233:5-7
      The type variable ‘f0’ is ambiguous
      These potential instances exist:
        instance Functor IO -- Defined in ‘GHC.Base’
        instance Functor Maybe -- Defined in ‘GHC.Base’
        instance Functor ((,) a) -- Defined in ‘GHC.Base’
        ...plus one other
        ...plus 9 instances involving out-of-scope types
        (use -fprint-potential-instances to see them all)
    • In the expression: f 4
      In an equation for ‘g’: g = f 4
    |
233 | g = f 4
    |     ^^^

So some guidance by the programmer is needed and it would readily be accepted if I could write g like this:

g :: (forall f. Functor f => Secret f) -> Int
g h = f 4 (\\f -> h @f)

Where \\ is hypothetical syntax for System Fw's big lambda, i.e. type abstraction. I can emulate this with ugly Proxys, but is there some other GHC Haskell feature that let's me write something like this?

like image 593
Sebastian Graf Avatar asked May 03 '18 15:05

Sebastian Graf


2 Answers

This might be a GHC bug. I can not see how this GHC behavior makes any sense.

This issue has nothing to do with type families, but it seems to arise from ambiguous types and typeclass constraints.

Here is a MCVE for the same issue.

{-# LANGUAGE AllowAmbiguousTypes    #-}
{-# LANGUAGE RankNTypes             #-}
{-# LANGUAGE TypeApplications       #-}

class C a where
   getInt :: Int

instance C Char where
   getInt = 42

f :: (forall a. C a => Int) -> Bool
f x = even (x @ Char)

g :: (forall a. C a => Int) -> Bool
-- g = f               -- fails
-- g h = f h           -- fails
-- g h = f getInt      -- fails
g _ = f 42             -- OK

It seems that f can not be called with any argument that actually exploits the constraint.

like image 66
chi Avatar answered Nov 16 '22 14:11

chi


This is by design. It seems there is no way around using Proxys for now: https://ghc.haskell.org/trac/ghc/ticket/15119.

Edit Jul 2019: There's now a GHC proposal for this!

like image 2
Sebastian Graf Avatar answered Nov 16 '22 15:11

Sebastian Graf