Haskell类型&多个文件

时间:2012-02-25 01:38:49

标签: haskell

假设我有一个简单的TCP服务,在接受连接时,会分叉一个新线程并调用 initializeClient clientSocket

initializeClient看起来像这样:

initializeClient clientSocket = do
    clientDataTVar <- atomically $ newTVar (UnregisteredClientData clientSocket)
    _ <- forkIO $ clientSocketReadLoop clientDataTVar

为简单起见,我们假设clientDataTVar中只有两个可能的实例:

data UnregisteredClientData = UnregisteredClientData {
  ucdSocket :: Socket
}

data CustomerClientData = CustomerClientData {
  ccdSocket :: Socket,
  ccdName :: Text
}

当未注册的客户端发送包含其名称的消息时,其ClientDataTVar值将被替换:

writeTVar unregisteredClientDataTVar $ CustomerClientData clientSocket theirName

编辑:上面的writeTVar行不会进行类型检查,因为TVar的类型是 TVar UnregisteredClientData 。 CustomerClientData无法写入其中,但我将其留在此处以说明我想要实现的目标。

此时,命令的处理程序返回,clientSocketReadLoop再次运行。

clientSocketReadLoop只对Socket感兴趣,所以我可以做以下事情:

class ClientData a where
  cdSocket :: a -> Socket

instance ClientData UnregisteredClientData where
  cdSocket = ucdSocket

instance ClientData CustomerClientData where
  cdSocket = ccdSocket

现在,当clientSocketReadLoop读取clientDataTVar,它可以调用的 cdSocket clientData 并检索插座,不管基本类型是UnregisteredClientData或CustomerClientData的。在执行recv之后,它需要调用一个处理程序。究竟要调用哪个处理程序取决于用户类型(未注册或客户)。

我相信这可以通过将handleMessage添加到类和实例来实现:

class ClientData a where
  cdSocket :: a -> Socket
  handleMessage :: a -> String -> IO ()

instance ClientData UnregisteredClientData where
  cdSocket = ucdSocket
  handleMessage unregisteredClientDataTVar msg = (implementation)

instance ClientData CustomerClientData where
  cdSocket = ccdSocket
  handleMessage customerClientDataTVar msg = (implementation)

因此,调用适当的处理程序。

我想知道的是:

这是一个很好的方法吗?我想这是一个相当标准的场景,虽然我使用TVar用于ClientData,而其他人可能只是通过Socket。这不应该有太大变化。

如果这是一个好方法,是否可以将类/实例定义放在一个文件(Types.hs)中并在另一个文件(Client.hs)中实现处理程序?

提前致谢!

1 个答案:

答案 0 :(得分:0)

我认为我不会在这里使用类型类。当你想要处理一小组有限的案例时,使用代数数据类型要简单得多。

例如,

data ClientData = ClientData { cdSocket :: Socket, cdName :: Maybe Text }

或者如果您想要比Maybe更明确的内容,

type Name = Text
data UserInfo = Unregistered | Customer Name
data ClientData = ClientData { cdSocket :: Socket, cdUserInfo :: UserInfo }

然后,您可以使用模式匹配来处理不同的情况:

handleMessage clientData msg =
  case cdUserInfo clientData of
    Unregistered  -> -- implementation
    Customer name -> -- implementation