Again on breaking loops at Haskell
source link: https://www.codesd.com/item/again-on-breaking-loops-at-haskell.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
Again on breaking loops at Haskell
I have a small piece of code that receives frames on a zeromq Pull socket and displays it in a opencv window:
module Main where
import Control.Monad
import qualified OpenCV as CV
import System.ZMQ4.Monadic
import System.Exit
main :: IO()
main = runZMQ $ do
receiver <- socket Pull
bind receiver "tcp://*:5554"
-- do some stuff not relevant
forever $ do
buffer <- receive receiver
let img = CV.imdecode CV.ImreadUnchanged buffer -- simple decoder
liftIO $ CV.withWindow "Video" $ \window -> do
CV.imshow window img
key <- CV.waitKey 10
when (key == 27) exitSuccess -- <- UGLY!
What I would like to find is a way to break the loop that allows me more control. I'm aware of the EitherT solution proposed by Gabriel Gonzalez here (that I like very much) but I'm not able to implement it in the CV.withWindow
context, for example:
quit :: (Monad m) => e -> EitherT e m r
quit = left
loop :: (Monad m) => EitherT e m a -> m e
loop = fmap (either id id) . runEitherT . forever
main :: IO()
main = runZMQ $ do
receiver <- socket Pull
bind receiver "tcp://*:5554"
loop $ do
buffer <- receive receiver
let img = CV.imdecode CV.ImreadUnchanged buffer -- simple decoder
liftIO $ CV.withWindow "Video" $ \window -> do
CV.imshow window img
key <- CV.waitKey 10
when (key == 27) $ quit ()
But of course quit
wraps the argument in a Left and this solution doesn't compile.
Read and write an IORef
, and use whileM_
.
main = runZMQ $ do
receiver <- socket Pull
bind receiver "tcp://*:5554"
continue <- liftIO $ newIORef True
whileM_ (liftIO $ readIORef continue) $ do
buffer <- receive receiver
let img = CV.imdecode CV.ImreadUnchanged buffer -- simple decoder
liftIO . CV.withWindow "Video" $ \window -> do
CV.imshow window img
key <- CV.waitKey 10
when (key == 27) $ writeIORef continue False
Or have your loop call itself explicitly as appropriate:
main = runZMQ $ do
receiver <- socket Pull
bind receiver "tcp://*:5554"
let loop = do
buffer <- receive receiver
let img = CV.imdecode CV.ImreadUnchanged buffer -- simple decoder
key <- liftIO . CV.withWindow "Video" $ \window -> do
CV.imshow window img
CV.waitKey 10
when (key /= 27) loop
loop
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK