Escribo una clase de tipo para mi biblioteca pipes
para definir una interfaz abstracta a tipos similares a Proxy
. El tipo de clase se ve algo como:Restringir una variable derivada de una clase de tipo o una instancia
class ProxyC p where
idT :: (Monad m) => b' -> p a' a b' b m r
(<-<) :: (Monad m)
=> (c' -> p b' b c' c m r)
-> (b' -> p a' a b' b m r)
-> (c' -> p a' a c' c m r)
... -- other methods
También estoy escribiendo extensiones para el tipo Proxy
que son de la forma:
instance (ProxyC p) => ProxyC (SomeExtension p) where ....
... y me gustaría que estas instancias de poder para imponer una restricción adicional que si m
es un Monad
entonces p a' a b' b m
es un Monad
para todos a'
, a
, b'
y b
.
Sin embargo, no tengo ni idea de cómo codificar limpiamente eso como una restricción ya sea para la clase ProxyC
o para las instancias. La única solución actualmente que conozco es hacer algo como lo codifica en las firmas de los métodos de la clase:
(<-<) :: (Monad m, Monad (p b' b c' c m), Monad (p a' a b' b m))
=> (c' -> p b' b c' c m r)
-> (b' -> p a' a b' b m r)
-> (c' -> p a' a c' c m r)
... pero esperaba que habría una solución más simple y más elegante.
Editar: Y ni siquiera esa última solución funciona, ya que el compilador no deduce que (Monad (SomeExtension p a' a b' b m))
implica (Monad (p a' a b' b m))
para una elección específica de las variables, incluso cuando se administra el siguiente ejemplo:
instance (Monad (p a b m)) => Monad (SomeExtension p a b m) where ...
Edición # 2: la siguiente solución que estoy considerando es sólo la duplicación de los métodos para la clase Monad
dentro de la clase ProxyC
:
class ProxyC p where
return' :: (Monad m) => r -> p a' a b' b m r
(!>=) :: (Monad m) => ...
... y luego instanciarlos con cada instancia ProxyC
. Esto parece estar bien para mis propósitos, ya que los métodos Monad
solo necesitan ser usados internamente para la escritura de extensiones y el tipo original todavía tiene una instancia apropiada Monad
para el usuario intermedio. Todo lo que hace es simplemente exponer los métodos Monad
al escritor de instancias.
AFAIK solo puedes hacerlo con hacks feos, como por ejemplo f.e. Edward Kmett lo hace en http://hackage.haskell.org/packages/archive/constraints/0.3.2/doc/html/Data-Constraint-Forall.html –