Haskell 网络套接字 header

Haskell websockets header

我正在尝试阅读 haskell 中的 websockets header。

当前代码如下

import Network
import Network.Socket.Internal
import Text.Printf
import Control.Monad
import Control.Monad.IO.Class
import Data.Maybe
import Data.List
import Data.Digest.Pure.SHA (bytestringDigest, sha1)
import Text.Regex
import System.IO

port :: Int
port = 8080

bufferLength :: Int
bufferLength = 2048

keyRegex :: String
keyRegex = "Sec-WebSocket-Key: (.+)(\r)"

response :: String
response = "HTTP/1.1 101 Web Socket Protocol Handshake\r\nUpgrade:     WebSocket\r\nConnection: Upgrade\r\nsec-websocket-accept:     changethis\r\n\r\n"

guidString :: String
guidString = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"

talk :: MonadIO m => Handle -> m String
talk handle = do liftIO $ hGetContents handle

main :: IO()
main = withSocketsDo $ do
  sock <- listenOn (PortNumber (fromIntegral port))
  printf "Listening on port %d\n" port
  forever $ do
    (handle, host, port) <- accept sock
    printf "Accepted connection from %s: %s\n" host (show port)
    hSetBuffering handle NoBuffering
    putStrLn $ talk handle

代码抛出错误

Main.hs:38:16:
    Couldn't match type `[Char]' with `Char'
    Expected type: String
      Actual type: [String]
    In the return type of a call of `talk'
    In the second argument of `($)', namely `talk handle'
    In a stmt of a 'do' block: putStrLn $ talk handle

如何打印header字符串? Talk 函数应该获取 header 字符串并 return 它被打印出来。

Return talk handle 的类型是 (MonadIO m => m String)

putStrLn 的类型为 String -> IO ()[Char] -> IO ().

[] 是一个单子。

putStrLn 需要一个字符列表,但它得到的值是 (MonadIO m => m String).

m 变成一个列表,putStrLn 得到一个 [String] 类型的值,这是错误的。


正如@Zeta 建议的那样,使用 talk handle >>= putStrLn 代替:

>>= 是允许使用另一次计算的结果继续计算的运算符。在你的情况下,你可以阅读 talk handle >>= putStrLn 如下:

talk handle -- first compute it
  >>= putStrLn -- then take string from result of `talk handle` and print it

不会有任何像 putStrLn $ talk handle:

这样的错误
(>>=)                        :: Monad m => m a -> (a -> m b) -> m b
talk handle                  :: MonadIO m => m String
(>>=) (talk handle)          :: MonadIO m => (String -> m b) -> m b  
putStrLn                     :: String -> IO ()
(>>=) (talk handle) putStrLn :: IO () -- `m` becomes `IO`    

已编辑:

在这里你可以找到 IO monad 的介绍:LYHFGG, Input and Output

在这里您可以找到对 monad 的一般介绍:LYHFGG, A Fistful of Monads

您应该了解 FunctorApplicative 才能阅读 A Fistful of Monads。无论如何你都可以在书的内容中找到它。