简体   繁体   English

如何在Haskell中通过管道使用ZMQ用户

[英]How to use a ZMQ subscriber in Haskell with pipes

I can get a ZMQ subscriber to work in Haskell, but would appreciate guidance on how to use that data with Pipes. 我可以让ZMQ订户在Haskell中工作,但希望能获得有关如何在Pipes中使用该数据的指导。 My attempt at writing a Producer fails at 'stack build' with the following error: 我写生产者的尝试在“堆栈生成”中失败,并出现以下错误:

Couldn't match type 'Proxy X () c'0 c0 (ZMQ z)' with 'ZMQ z' 无法将类型“代理X()c'0 c0(ZMQ z)”与“ ZMQ z”进行匹配

Expected type: ZMQ z () 预期类型:ZMQ z()

Actual type: Proxy X () c'0 c0 (ZMQ z) () 实际类型:代理X()c'0 c0(ZMQ z)()

{-# LANGUAGE OverloadedStrings #-}
module Main where
import Control.Monad
import Pipes
import qualified Pipes.Prelude as P
import System.ZMQ4.Monadic
import qualified Data.ByteString.Char8 as CS

fromZMQ :: (Receiver r) => Socket z r -> Producer String (ZMQ z) ()
fromZMQ sock = do
    msg <- lift $ receive sock
    yield (CS.unpack msg)
    fromZMQ sock

main :: IO ()
main = --do
  runZMQ $ do
    subSock <- socket Sub  ---subscriptionSocket
    subscribe subSock ""
    connect subSock "tcp://127.0.0.1:4998" 
    forever $ fromZMQ subSock >-> P.take 3 >-> P.print

Note, I want to consume data being published on ZMQ by a python script. 注意,我想使用通过python脚本在ZMQ上发布的数据。

Working off Thomas' suggestion of using Chan, I adapted the MVar example (link below) to accumulate the strings received and a count of them to demonstrate updating and reading state 根据Thomas提出的使用Chan的建议,我改编了MVar示例(下面的链接)以累加接收到的字符串,并计算其中的一部分以演示更新和读取状态

https://www.oreilly.com/library/view/parallel-and-concurrent/9781449335939/ch07.html https://www.oreilly.com/library/view/parallel-and-concurrent/9781449335939/ch07.html

{-# LANGUAGE OverloadedStrings #-}

module Main where

import Control.Concurrent  
import Control.Monad
import System.ZMQ4.Monadic
import qualified Data.ByteString.Char8 as CS

newtype State = State (MVar (Int, [CS.ByteString]) ) --(count, list of strings received over zmq)

newState :: IO State
newState = do
  m <- newMVar (0, [])
  return (State m)

updateState :: State -> CS.ByteString -> IO ()
updateState (State m) newString = do
  (count,strList) <- takeMVar m
  putMVar m ( count + 1 , strList ++ [newString] )

showState :: State -> IO String
showState (State m) = do
  count <- takeMVar m
  putMVar m count  --return the lock; no changes
  return (show count)

main = runZMQ $ do
    sub <- socket Sub
    subscribe sub ""
    connect sub "tcp://127.0.0.1:4998"
    s <- liftIO newState 
    forever $ do
      receive sub >>= liftIO . updateState s 
      liftIO $ updateState s "hello"  --'manually' add an additional string on each iteration
      op <- liftIO $ showState s
      liftIO $ print op 

The only problem in your code is the last line. 代码中唯一的问题是最后一行。

You have a “pipe” there: 您在那里有一个“管道”:

fromZMQ subSock >-> P.take 3 >-> P.print :: Effect (ZMQ z) ()

and when you apply forever to it, the type remains the same. 当您forever申请时,类型保持不变。 But what you need there is a simple ZMQ z , in other words, you need to actually perform the pipes computation and you use the runEffect function for this. 但是,您需要一个简单的ZMQ z ,换句话说,您需要实际执行pipes计算,并为此使用runEffect函数。 As a side note, you don't really need the forever as the stream will never end anyway. 附带说明一下,您实际上并不需要forever因为流永远不会结束。

So, all you have to do, really, is replace forever with runEffect in the last line. 因此,实际上,您要做的就是最后一行中的runEffect forever替换。

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

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