用方法返回相同的Class对象

时间:2016-08-23 10:08:34

标签: haskell

我在haskell写一个聊天服务器。早些时候我有tcp套接字。现在我转向WebSockets。我想在它上面创建一个NetworkConn的瘦包装..我在编写accept函数时遇到了问题。

acceptReuqest PendingConnection返回Connection

fst <$> accept SocketSocket

所以,我试过跟随.. 为NetworkConn

创建Socket, Connection, PendingConnection
class NetworkConn sock where
  accept :: (NetworkConn myconn) => sock -> IO myconn

instance NetworkConn NS.Socket where
  accept sock    = fst <$> NS.accept sock

instance NetworkConn WS.Connection where
  accept sock    = error "Not allowed"

acceptReuqest PendingConnection返回Connection

instance NetworkConn WS.PendingConnection where
  accept sock = WS.acceptRequest sock

这给我NS.Socket中的错误

Couldn't match type ‘myconn’ with ‘NS.Socket’
      ‘myconn’ is a rigid type variable bound by
               the type signature for
                 acceptC :: NetworkConn myconn => NS.Socket -> IO myconn
               at src/HChat/Network.hs:21:3
    Expected type: IO
                     (myconn, network-2.6.2.1:Network.Socket.Types.SockAddr)
      Actual type: IO
                     (NS.Socket, network-2.6.2.1:Network.Socket.Types.SockAddr)
    Relevant bindings include
      acceptC :: NS.Socket -> IO myconn
        (bound at src/HChat/Network.hs:21:3)
    In the second argument of ‘(<$>)’, namely ‘NS.accept sock’
    In the expression: fst <$> NS.accept sock

Couldn't match type ‘myconn’ with ‘WS.Connection’
      ‘myconn’ is a rigid type variable bound by
               the type signature for
                 acceptC :: NetworkConn myconn => WS.PendingConnection -> IO myconn
               at src/HChat/Network.hs:31:3
    Expected type: IO myconn
      Actual type: IO WS.Connection
    Relevant bindings include
      acceptC :: WS.PendingConnection -> IO myconn
        (bound at src/HChat/Network.hs:31:3)

我开始阅读class并且无法理解为什么会出现错误。 我想这是一个语法错误,但无法弄清楚。请帮忙。

是否可以将返回类型限制为NetworkConn,因为我只想调用仅在NetworkConn中定义的几个方法。?

尝试两个课程:

class CandidateConn c where
  acceptC :: (NetworkConn s) => c -> IO s

class NetworkConn sock where
  send :: sock -> C.ByteString -> IO ()
  recv :: sock -> IO C.ByteString
  accept :: (CandidateConn conn) => conn -> IO sock

instance NetworkConn NS.Socket where
  send sock text = void $ NSB.send sock text
  recv sock      = NSB.recv sock 1024
  accept c       = acceptC c

instance CandidateConn NS.Socket where
  acceptC sock = fst <$> NS.accept sock

给出:

Couldn't match type ‘s’ with ‘NS.Socket’
      ‘s’ is a rigid type variable bound by
          the type signature for
            acceptC :: NetworkConn s => NS.Socket -> IO s
          at src/HChat/Network.hs:29:3
    Expected type: IO
                     (s, network-2.6.2.1:Network.Socket.Types.SockAddr)
      Actual type: IO
                     (NS.Socket, network-2.6.2.1:Network.Socket.Types.SockAddr)
    Relevant bindings include
      acceptC :: NS.Socket -> IO s (bound at src/HChat/Network.hs:29:3)

3 个答案:

答案 0 :(得分:3)

此类型签名:

class NetworkConn sock where
  accept :: (NetworkConn myconn) => sock -> IO myconn

说,“作为sock的{​​{1}}类型提供了一个函数NetworkConn,它接受​​accept并返回一个操作,从而产生调用者所需的任何类型,如只要该类型依次为sock。“

这是你不能坚持的承诺。你可能想写一下它返回“某些特定于NetworkConn的类型,它也实现了sock”。这就是相关类型的用途。

粗略地说,您启用了TypeFamilies扩展,然后编写

NetworkConn

除此之外缺少class NetworkConn sock where type AcceptedConn sock :: * accept :: sock -> IO (AcceptedConn sock) 的{​​{1}}约束。我很难找到正确的语法来表达这一点,目前无法进行语法检查,但你可以试试这个:

NetworkConn

我认为这需要启用FlexibleInstances。

然后,实例声明变为:

AcceptedConn

正如我所说,我根本没有对此进行语法检查。

答案 1 :(得分:1)

怎么样

class NetworkConn sock where
  accept :: sock -> IO sock

你写的是一个通用的返回类型,而我认为你的accept方法只返回特定的连接类型。

如果您确实需要动态返回,则可能需要2个类型类,如

class CandidateConn sock where
  -- some methods
class NetworkConn sock where
  accept :: CandidateConn c => c -> IO sock

答案 2 :(得分:1)

#haskell irc频道的高贵灵魂{As}建议使用https://wiki.haskell.org/Multi-parameter_type_class

它有效..谢谢{As}

{-# LANGUAGE MultiParamTypeClasses #-}

module HChat.Network where

-- For Network.Socket library
import qualified Network.Socket as NS (Socket, accept)
import qualified Network.Socket.ByteString as NSB (send, recv)
import qualified Data.ByteString.Char8 as C

-- For WebSockets library
import qualified Network.WebSockets as WS

import Control.Monad (void)

class NetworkConn sock conn where
  send :: conn -> C.ByteString -> IO ()
  recv :: conn -> IO C.ByteString
  accept :: sock -> IO conn

instance NetworkConn NS.Socket NS.Socket where
  send conn text = void $ NSB.send conn text
  recv conn      = NSB.recv conn 1024
  accept sock    = fst <$> NS.accept sock

instance NetworkConn WS.PendingConnection WS.Connection where
  send sock text = WS.sendTextData sock text
  recv sock      = WS.receiveData sock
  accept sock    = WS.acceptRequest sock