2012-10-03 65 views
7

tengo algún tipo artificial:restricción polimórfico

{-# LANGUAGE DeriveFunctor #-} 

data T a = T a deriving (Functor) 

... y ese tipo es la instancia de alguna clase artificial:

class C t where 
    toInt :: t -> Int 

instance C (T a) where 
    toInt _ = 0 

¿Cómo puedo expresar en una restricción de la función que es T a una instancia de alguna clase para todos a?

Por ejemplo, considere la siguiente función:

f t = toInt $ fmap Left t 

Intuitivamente, yo esperaría que la función anterior para trabajar desde toInt trabajos sobre T a para todos a, pero no puedo expresar que en el tipo. Esto no funciona:

f :: (Functor t, C (t a)) => t a -> Int 

... porque cuando aplicamos fmap el tipo se ha convertido en Either a b. No puedo solucionar este problema usando:

f :: (Functor t, C (t (Either a b))) => t a -> Int 

... porque b no representa una variable cuantificada universalmente. Tampoco puedo decir:

f :: (Functor t, C (t x)) => t a -> Int 

... o utilizar forall x que sugieren que la restricción es válida para todos x.

Así que mi pregunta es si hay una manera de decir que una restricción es polimórfica sobre algunas de sus variables de tipo.

+0

que suponer que algo como 'clase C t donde Toint :: ta -> Int' no va a funcionar, y lo que necesita 'C' sea de tipo' * -> Restricción'? ¿El polimorfismo bueno ayudaría aquí? –

+0

@ C.A.McCann El constructor de tipo concreto que tengo en mente es 'Proxy' de' pipes' y la clase concreta es 'Monad'. Estoy clasificando funciones de utilidad para tipos similares a proxy, por lo que la restricción está ahí. Siguiendo su sugerencia, definiría una clase 'MonadP' especializada en la forma del constructor de tipo' Proxy' y la utilizaría como una restricción. La desventaja es que si los usuarios quisieran escribir funciones de utilidad de proxy polimórficas en el tipo proxy, tendrían que volver a enlazar notación do para usar 'MonadP' en su lugar. –

+2

No puede hacerlo directamente, pero es posible simular, como en la respuesta de Roman. Aquí está el boleto relevante de GHC: http://hackage.haskell.org/trac/ghc/ticket/2893 – glaebhoerl

Respuesta

6

Usando el paquete de constraints:

{-# LANGUAGE FlexibleContexts, ConstraintKinds, DeriveFunctor, TypeOperators #-} 

import Data.Constraint 
import Data.Constraint.Forall 

data T a = T a deriving (Functor) 

class C t where 
    toInt :: t -> Int 

instance C (T a) where 
    toInt _ = 0 

f :: ForallF C T => T a -> Int 
f t = (toInt $ fmap Left t) \\ (instF :: ForallF C T :- C (T (Either a b))) 
+3

También vale la pena mirar el origen de ese 'ForallF', aunque solo sea para admirar lo simple/feo/aterrador que es la idea detrás de es :) – copumpkin

+0

@copumpkin: en realidad tengo una pregunta al respecto - http://stackoverflow.com/questions/12728159/how-does-the-constraints-package-work –