我正在为我的pipes
库编写一个类型类来定义一个类类型的抽象接口Proxy
。类型类看起来像:
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
我还在为以下Proxy
形式的类型编写扩展:
instance (ProxyC p) => ProxyC (SomeExtension p) where ....
...并且我希望这些实例能够施加额外的约束,即 ifm
是 a Monad
thenp a' a b' b m
是 aMonad
对于所有a'
, a
, b'
, and b
.
但是,我不知道如何将其干净地编码为ProxyC
类或实例的约束。我目前知道的唯一解决方案是在类的方法签名中进行编码:
(<-<) :: (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)
...但我希望会有一个更简单、更优雅的解决方案。
编辑:甚至最后一个解决方案也不起作用,因为编译器不会推断出这(Monad (SomeExtension p a' a b' b m))
意味着(Monad (p a' a b' b m))
特定的变量选择,即使给出以下实例:
instance (Monad (p a b m)) => Monad (SomeExtension p a b m) where ...
编辑#2:我正在考虑的下一个解决方案只是在Monad
类中复制类的方法ProxyC
:
class ProxyC p where
return' :: (Monad m) => r -> p a' a b' b m r
(!>=) :: (Monad m) => ...
...然后用每个ProxyC
实例实例化它们。这对我的目的来说似乎没问题,因为这些Monad
方法只需要在内部用于扩展编写,并且原始类型仍然有一个适合Monad
下游用户的实例。所有这些只是将Monad
方法公开给实例编写器。