2016-09-22 1 views
5

Ich habe mit einigen GHC Erweiterungen spielen eine Funktion zu definieren, die folgendes tun:Receiving als Argument Funktionen mit Constrained Existenziale in Haskell

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

myFunc sollte in der Signatur von show vollständig polymorph sein, so dass es a und b mit verschiedenen Typen annehmen kann, die Show erfüllen.

Hier ist mein Versuch, mit den GHC Erweiterungen RankNTypes, ConstraintKinds, KindSignatures:

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

Mein Hauptziel ist es, zu verstehen, wie diese Erweiterungen arbeiten; aber in meinen Augen, so scheint es, wie ich GHC sage, dass es eine Einschränkung k, dass einige a und b erfüllen, und es gibt auch eine Funktion (forall c. k c => c -> d), die jede Art nehmen ck erfüllen und das Rück eine bestimmte d, jetzt, unter diesen Bedingungen ich möchte die Funktion a und b anzuwenden, um ein Tupel erhalten (d,d)

Hier ist, wie GHC klagt:

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 

Was bin ich?

+1

Ich nehme an, Sie in den Einschränkungen kann das Funktionsargument polymorphen bedeuten haben, denn sonst Du könntest einfach schreiben: (Zeige a, Zeige b) => (forall x. Zeige x => x -> String) -> a -> b -> (String, String) '? Das erfordert nur 'RankNTypes'. – Cubic

+0

Das stimmt, ich will nicht von 'Show' sprechen. – enobayram

Antwort

5

Das Problem ist, dass nur die Funktion (forall c . k c => c -> d) als Argument übergeben ist nicht genug für den Typ-Checker eindeutig zu bestimmen, was k wirklich ist. die Einschränkung ausdrücklich Passing funktioniert und Sie brauchen nicht einmal die äußeren forall oder explizite Arten:

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) 

und dann

let (c, d) = myFunc (Proxy :: Proxy Show) show a b 
+0

Ich sehe, vielen Dank; Das erklärt auch, was GHC bedeutet. Um die Mehrdeutigkeitsprüfung für die Verwendung von Websites zu verzögern, aktivieren Sie AllowAmboundTypes, da ich normalerweise erwarte, dass diese Prüfung auf der Aufrufseite stattfindet. Natürlich denkt Haskells Typsystem immer daran, die Probleme lokal zu erfassen, anders als beispielsweise C++ - Vorlagen, die fast alles auf die Instanziierung zurückstellen. – enobayram

+2

Mit GHC8 bietet die Verwendung von "-XAllowAmboundyTypes" und "-XTypeApplications" eine andere Lösung. Das Argument "Proxy" verschwindet, und Sie haben dann "myFunc f a b = (f a, f b)" und "myFunc @Show show a b" an der Call-Site. –

Verwandte Themen