【发布时间】:2011-12-30 03:11:05
【问题描述】:
我想将带有字段 sType 的 Data 类型表示为任何 SType 实例(来自 zeromq-haskell)。 SType 是 zeromq 套接字类型。在 zeromq-haskell 源代码中,一个例子是这样的:
data Pair = Pair
instance SType Pair where
zmqSocketType = const pair
这就是我现在所拥有的
data SocketOpts = SocketOpts
{ end :: SocketEnd
, sType :: SType st => st
}
但是当我像这样使用它socket ctx $ sType so 我得到:
Ambiguous type variable `a0' in the constraint:
(SType a0) arising from a use of `sType'
(socket的签名是socket :: SType a => Context -> a -> IO (Socket a)
当我尝试在 ghci 中创建一个 SocketOpts 时,我得到:
let so = SocketOpts (Bind "some") Pull
<interactive>:1:35:
Could not deduce (st ~ Pull)
from the context (SType st)
bound by a type expected by the context: SType st => st
at <interactive>:1:10-38
`st' is a rigid type variable bound by
a type expected by the context: SType st => st
at <interactive>:1:10
In the second argument of `SocketOpts', namely `Pull'
In the expression: SocketOpts (Bind "some") Pull
In an equation for `so': so = SocketOpts (Bind "some") Pull
我从中了解到的是,SType 比我所要求的更通用(Pull,它是 SType 的一个实例)。在这里我应该如何表达我想要的?
编辑
这个:
data SocketOpts st = SocketOpts
{ end :: SocketEnd
, sType :: st
}
结合使用:
zmqSource :: (ResourceIO m, SType st) => Context -> SocketOpts st -> Source m a
zmqSource ctx so = sourceIO
mkSocket
recvSock
(\x -> undefined)
where
recvSock = undefined
mkSocket = socket ctx $ sType so
似乎有效,但如果有更优雅的方法可以做到这一点,我会留下问题?
编辑 2
各位,非常感谢您的回答。根据您的反馈,我现在得到了以下内容(我不会在这里发布,因为在 github 上更容易阅读)
https://github.com/boothead/zeromq-conduit/blob/master/Data/Conduit/ZMQ.hs
我已经使用 GADT(我认为)来尝试表达设置普通套接字和子套接字之间的区别,但目前有一个问题:我可以使用 SockOpts 类型来设置子套接字在这种情况下 subscribe 不会被调用并且它不起作用:
SockOpts (Connect "tcp://127.0.0.1:9999") Sub -- This would be bad
有没有办法让类型系统禁止这样做?类似于我在尖括号中的内容?
SockOpts :: (SType st, <not SubsType st>) => SocketEnd -> st -> SocketOpts st
【问题讨论】: