简体   繁体   English

Haskell类型类和多个文件

[英]Haskell type classes & multiple files

Suppose I have a simple TCP service which, upon accepting a connection, forks a new thread and calls initializeClient clientSocket . 假设我有一个简单的TCP服务,接受连接后,它会派生一个新线程并调用initializeClient clientSocket

initializeClient looks like this: initializeClient如下所示:

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

For simplicity, let's suppose there are only 2 possible instances in clientDataTVar: 为了简单起见,让我们假设clientDataTVar中只有两个可能的实例:

data UnregisteredClientData = UnregisteredClientData {
  ucdSocket :: Socket
}

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

When an Unregistered client sends a message containing their name, their ClientDataTVar value gets replaced: 当未注册的客户端发送包含其名称的消息时,其ClientDataTVar值将被替换:

writeTVar unregisteredClientDataTVar $ CustomerClientData clientSocket theirName

Edit : The above writeTVar line won't typecheck, because the type of the TVar is TVar UnregisteredClientData . 编辑 :上面的writeTVar行将不会进行类型检查,因为TVar的类型是TVar UnregisteredClientData CustomerClientData cannot be written into it, but I'm leaving it here to illustrate what I'm trying to achieve. 无法将CustomerClientData写入其中,但我将其留在此处以说明我要实现的目标。

at which point, the handler for the command returns and clientSocketReadLoop runs again. 此时,命令的处理程序将返回,并且clientSocketReadLoop再次运行。

clientSocketReadLoop is only interested in the Socket, so I could do the following: clientSocketReadLoop只对套接字感兴趣,因此我可以执行以下操作:

class ClientData a where
  cdSocket :: a -> Socket

instance ClientData UnregisteredClientData where
  cdSocket = ucdSocket

instance ClientData CustomerClientData where
  cdSocket = ccdSocket

Now, when clientSocketReadLoop reads clientDataTVar, it can call cdSocket clientData and retrieve the Socket, regardless of the underlying type being UnregisteredClientData or CustomerClientData. 现在,当clientSocketReadLoop读取clientDataTVar时,无论基础类型是UnregisteredClientData还是CustomerClientData,它都可以调用cdSocket clientData并检索Socket。 After it does the recv, it needs to call a handler. 执行接收后,需要调用处理程序。 Exactly which handler to call depends on the type of user (Unregistered or Customer). 究竟要调用哪个处理程序取决于用户的类型(未注册或客户)。

I believe this can be achieved by adding handleMessage to the class and instances: 我相信可以通过在类和实例中添加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)

Thus, the appropriate handler is called. 因此,将调用适当的处理程序。

What I'd like to know is: 我想知道的是:

Is this a good way to do it? 这是一个好方法吗? I'd imagine it's a fairly standard scenario, although I use a TVar for ClientData while others might just pass the Socket around. 我以为这是一个相当标准的场景,尽管我将TVar用于ClientData,而其他人可能只是通过Socket。 This shouldn't change much. 这应该不会有太大变化。

If it is a good way, is it possible to have the class/instance definitions in one file (Types.hs) and implement the handlers in another file (Client.hs)? 如果这是一个好方法,是否可以在一个文件(Types.hs)中包含类/实例定义,并在另一个文件(Client.hs)中实现处理程序?

Thanks in advance! 提前致谢!

I don't think I would use a type class here. 我不认为我会在这里使用类型类。 When you have a small and limited set of cases you wish to work on, it's much simpler to just use an algebraic data type. 当您希望处理的案例很少且数量有限时,仅使用代数数据类型会简单得多。

For example, 例如,

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

or if you want something more explicit than a Maybe , 或者,如果您想要比Maybe更明确的内容,

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

You can then just use pattern matching to handle the different cases: 然后,您可以只使用模式匹配来处理不同的情况:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM