haskell - Pipes-2.1.0 包中的最终确定

标签 haskell monads categories monad-transformers loops

我正在使用 Pipes-2.1.0 包和 Zeromq3-haskell 包来构建一个小型消息管道。一切似乎都很顺利,除了我无法理解框架的最终确定。

在下面的框架中我获取了两个资源;一个 Zeromq 上下文和一个 Zeromq 套接字。然后我不断等待消息(以ByteStrings的形式)在zeromq套接字上发布。

{-# LANGUAGE RebindableSyntax    #-}
{-# LANGUAGE ScopedTypeVariables #-}

module PipesZeroMQ where

import           Control.Frame
import           Control.IMonad.Do
import           Control.IMonad.Trans
import qualified Control.Monad          as M
import           Data.ByteString        (ByteString)
import           Data.String
import           Prelude                hiding (Monad(..))
import qualified System.ZMQ3            as ZMQ

type Address = String

fromList :: (M.Monad m) => [b] -> Frame b m (M a) (M a) ()
fromList xs = mapMR_ yield xs

publisher :: Address -> Frame Void IO (M ByteString) C ()
publisher addr = do
  c  <- liftU $ ZMQ.init 1
  s  <-liftU $ ZMQ.socket c ZMQ.Pub
  liftU $ ZMQ.bind s addr   
  liftU $ print "Socket open for business!!!"

  foreverR $ do
    bs <- await
    finallyF (ZMQ.close s M.>> ZMQ.term c M.>> print "ZMQ socket closed") $ do
         (liftU $ ZMQ.send s [] bs)
         (liftU (print "Sending message"))

现在如果我尝试这个:

λ> runFrame $ (publisher localAddress) <-< (fromList ["This", "that", "that"] >> close)

我明白了:

"Socket open for business"
"Sending message"
"ZMQ socket closed"
*** Exception: ZMQError { errno = 88, source = "send", message = "Socket operation on non-socket" }

publisher 在收到一个 BytesString 后完成。

为什么会发生这种情况?

我对 Pipes-2.1.0 中使用框架的终结有什么误解?

如果我开始攻击外面的树,它还有机会吗?

最佳答案

您在编写 publisher 函数时犯了一个错误:

foreverR $ do
    bs <- await
    finallyF (ZMQ.close s M.>> ZMQ.term c M.>> print "ZMQ socket closed") $ do
         (liftU $ ZMQ.send s [] bs)
         (liftU (print "Sending message"))

您可能想将 finallyF 放在 foreverR 循环之外:

finallyF (...) $ foreverR $ do
    bs <- await
    liftU $ ZMQ.send s [] bs)
    liftU (print "Sending message")

按照您编写的方式,它会在每次发送后完成,因此它完全按照您的指示执行操作:每次发送后完成。一旦它包装的操作完成,finallyF 就会调用终结器,无论它成功终止还是失败。在这种情况下,您也可以使用catchF,因为循环永远不会终止:

 catchF (...) $ foreverR $ do
    bs <- await
    liftU $ ZMQ.send s [] bs)
    liftU (print "Sending message")

或者,您可以将其保留在循环内,但切换到catchF,以便终结器不会在每次发送后运行:

foreverR $ do
    bs <- await
    catchF (ZMQ.close s M.>> ZMQ.term c M.>> print "ZMQ socket closed") $ do
         (liftU $ ZMQ.send s [] bs)
         (liftU (print "Sending message"))

此外,如果您计划编写一个基于管道的 ZeroMQ 库,请与我联系,因为我计划在下一个版本中将帧返回到普通 monad,并提供许多新的功能增强功能,例如关闭和重新初始化资源的能力。要联系我,请使用我的 gmail.com 地址和用户名 Gabriel439。

关于haskell - Pipes-2.1.0 包中的最终确定,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11479611/

相关文章:

ruby-on-rails - 如何在Rails中创建类别

haskell - 如何解析无序语法

haskell - 如何在带有 do 表示法的列表上使用 map - 即避免使用 `IO ()' 类型的 `[IO ()]' 类型?

objective-c - 是否有可能有一个 "#pragma mark"层次结构?

scala - 如何将 Seq[Reader[E, A]]) 转换为 Reader[E, Seq[A]]

haskell - Monad 作为附加词

Objective-C if ([self isKindOfClass : . .. ]) 静态方法

performance - 在Haskell中执行恒定空间嵌套循环的正确方法是什么?

haskell - 在 Eq 实例实现中仅覆盖少数情况的数据

database - haskell 与甲骨文