I can get a ZMQ subscriber to work in Haskell, but would appreciate guidance on how to use that data with 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'
Expected type: ZMQ z ()
Actual type: Proxy 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.
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
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. 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. As a side note, you don't really need the forever
as the stream will never end anyway.
So, all you have to do, really, is replace forever
with runEffect
in the last line.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.