Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Receiving as Argument Functions with Constrained Existentials in Haskell

I've been playing with some GHC extensions to define a function that can do the following:

let a = A :: A  -- Show A
    b = B :: B  -- Show B
  in
    myFunc show a b -- This should return (String, String)

myFunc should be fully polymorphic in the signature of show, so that it can accept a and b with different types satisfying Show.

Here's my attempt with the GHC extensions RankNTypes, ConstraintKinds, KindSignatures:

myFunc :: forall (k :: * -> Constraint) a b d. (k a, k b) 
            => (forall c. k c => c -> d) -> a -> b -> (d, d)

My main purpose is to understand how these extensions work; but to my eyes, it seems like I'm telling GHC that there's a constraint k that some a and b satisfy, and there's also a function (forall c. k c => c -> d) that can take any type c satisfying k and return a specific d, now, under these conditions, I want to apply the function to a and b to obtain a tuple (d,d)

Here's how GHC complains:

Could not deduce (k0 a, k0 b)
from the context (k a, k b)
  bound by the type signature for
             myFunc :: (k a, k b) =>
                       (forall c. k c => c -> d) -> a -> b -> (d, d)
  at app/Main.hs:(15,11)-(16,56)
In the ambiguity check for the type signature for ‘myFunc’:
  myFunc :: forall (k :: * -> Constraint) a b d.
            (k a, k b) =>
            (forall c. k c => c -> d) -> a -> b -> (d, d)
To defer the ambiguity check to use sites, enable AllowAmbiguousTypes
In the type signature for ‘myFunc’:
  myFunc :: forall (k :: * -> Constraint) a b d. (k a, k b) =>
            (forall c. k c => c -> d) -> a -> b -> (d, d)

...

Could not deduce (k c)
from the context (k a, k b)
  bound by the type signature for
             myFunc :: (k a, k b) =>
                       (forall c. k c => c -> d) -> a -> b -> (d, d)
  at app/Main.hs:(15,11)-(16,56)
or from (k0 c)
  bound by the type signature for myFunc :: k0 c => c -> d
  at app/Main.hs:(15,11)-(16,56)
In the ambiguity check for the type signature for ‘myFunc’:
  myFunc :: forall (k :: * -> Constraint) a b d.
            (k a, k b) =>
            (forall c. k c => c -> d) -> a -> b -> (d, d)
To defer the ambiguity check to use sites, enable AllowAmbiguousTypes
In the type signature for ‘myFunc’:
  myFunc :: forall (k :: * -> Constraint) a b d. (k a, k b) =>
            (forall c. k c => c -> d) -> a -> b -> (d, d)
app/Main.hs15:40

What am I missing?

like image 434
enobayram Avatar asked Sep 22 '16 07:09

enobayram


1 Answers

The problem is that just passing the function (forall c . k c => c -> d) as an argument is not enough for the type-checker to unambiguously determine what k really is. Passing the constraint explicitly works and you don't even need the outer forall or explicit kinds:

import Data.Proxy

myFunc :: (k a, k b) => Proxy k -> (forall c. k c => c -> d) -> a -> b -> (d, d)
myFunc _ f a b = (f a, f b)

and then

let (c, d) = myFunc (Proxy :: Proxy Show) show a b
like image 185
shang Avatar answered Nov 15 '22 10:11

shang