Questo non può essere fatto in modo affidabile con i sinonimi di tipo. Hai bisogno di tipi esistenziali o di rango-n tipi.
Il problema è che Haskell consente ai sinonimi di tipo di essere completamente intersubituibili. Ad esempio, quando si definisce type Baz a b = Foo p a b
, in ogni contesto in cui si dispone di Foo p a b
, è possibile utilizzare Baz a b
e viceversa. Così, per esempio, se si ha una funzione di questo tipo:
f1 :: Foo Something a b -> Whatever Something b a
Poi a causa della sostituibilità, che sarebbe lo stesso tipo come questo:
f1 :: Baz a b -> Whatever Something b a
E come questo:
f1 :: Foo p a b -> Whatever Something b a
... che poi si potrebbe specializzarsi in questo:
f1 :: Foo SomethingElse a b -> Whatever Something b a
Quindi, cosa puoi fare? Uno è quello di definire un tipo di involucro esistenziale:
{-# LANGUAGE ExistentialTypes #-}
data Baz a b = forall p. Baz (Foo p a b)
modo alternativo di fare la stessa cosa:
{-# LANGUAGE GADTs #-}
data Baz a b where
Baz :: Foo p a b -> Baz a b
Secondo modo si potrebbe andare: tipi rango-N e stile continuazione-passing:
{-# LANGUAGE RankNTypes #-}
-- To consume one of these, you pass a "callback" function to `runBaz`,
-- which is not allowed to restrict the type variable `p`.
newtype Baz a b = Baz { runBaz :: forall p r. (Foo p a b -> r) -> r }
makeBaz :: Foo p a -> Baz a b
makeBaz foo = Baz ($foo)
Terzo modo, che hai tentato e (mi hanno detto) non funziona molto bene: digita sinonimi + tipi impredicativi (che sono necessari per ottenere i sinonimi di forall
come argomenti di tipo in molti casi).
Penso che tu stia cercando [questo tipo di comportamento] (http://www.reddit.com/r/haskell/comments/32k1eu/new_in_ghc_710_partial_type_signatures/cqbxmra), ma non è attualmente supportato. – rampion