Hints on how to remove unsafePerformIO from my function?

I am writing a voip server to take advantage of haskells awesome threading and parsing ability. At first everything was going great, but my thread that fetches udp makes use of unsafePerformIO: fetchUDPSIP :: TChan B.ByteString -> IO () fetchUDPSIP chan = do sock <- getUDPSocket 5060 let results = (unstrict . repeat . getUDP) sock mapM_ (atomically . writeTChan chan) results where unstrict [] = [] unstrict (x:xs) = unsafePerformIO x:unstrict xs It fetches it from a socket, and then writes it to a TChan. This results in a stream of bytestrings that another thread can read from. If I don't use unsafePerformIO, then it tries to read all possible packets before returning anything, and so it never writes to the TChan at all. The problem with doing it this way is that unsafePerformIO apparently stops every other thread from doing anything while it is waiting for a packet. But I can't think of a way to rewrite this function to do what I want. I'm kind of new to this, does anyone have any hints that could help me out? Here's a simple version without any of the implementation details: fetchLine = do let results = (unstrict . repeat) getLine mapM_ putStrLn results where unstrict [] = [] unstrict (x:xs) = unsafePerformIO x:unstrict xs

fork it into a thread and have it run on a loop, yielding if it can't read
any data from the udp socket?
On 19 July 2010 16:07, David McBride
I am writing a voip server to take advantage of haskells awesome threading and parsing ability. At first everything was going great, but my thread that fetches udp makes use of unsafePerformIO:
fetchUDPSIP :: TChan B.ByteString -> IO () fetchUDPSIP chan = do sock <- getUDPSocket 5060 let results = (unstrict . repeat . getUDP) sock mapM_ (atomically . writeTChan chan) results where unstrict [] = [] unstrict (x:xs) = unsafePerformIO x:unstrict xs
It fetches it from a socket, and then writes it to a TChan. This results in a stream of bytestrings that another thread can read from. If I don't use unsafePerformIO, then it tries to read all possible packets before returning anything, and so it never writes to the TChan at all. The problem with doing it this way is that unsafePerformIO apparently stops every other thread from doing anything while it is waiting for a packet.
But I can't think of a way to rewrite this function to do what I want. I'm kind of new to this, does anyone have any hints that could help me out?
Here's a simple version without any of the implementation details:
fetchLine = do let results = (unstrict . repeat) getLine mapM_ putStrLn results where unstrict [] = [] unstrict (x:xs) = unsafePerformIO x:unstrict xs
_______________________________________________ Beginners mailing list Beginners@haskell.org http://www.haskell.org/mailman/listinfo/beginners

Well, I thought about that, but I can't find anything in the network.socket
library that would allow me to see if there is any data ready to be read
from.
But besides that, wouldn't that cause a busy wait as the thread constantly
failed to read and yielded over and over again until there was a new
packet? I'd rather if this thread chilled out until something worthwhile
occurs.
On Mon, Jul 19, 2010 at 10:12 AM, Benjamin Edwards
fork it into a thread and have it run on a loop, yielding if it can't read any data from the udp socket?
On 19 July 2010 16:07, David McBride
wrote: I am writing a voip server to take advantage of haskells awesome threading and parsing ability. At first everything was going great, but my thread that fetches udp makes use of unsafePerformIO:
fetchUDPSIP :: TChan B.ByteString -> IO () fetchUDPSIP chan = do sock <- getUDPSocket 5060 let results = (unstrict . repeat . getUDP) sock mapM_ (atomically . writeTChan chan) results where unstrict [] = [] unstrict (x:xs) = unsafePerformIO x:unstrict xs
It fetches it from a socket, and then writes it to a TChan. This results in a stream of bytestrings that another thread can read from. If I don't use unsafePerformIO, then it tries to read all possible packets before returning anything, and so it never writes to the TChan at all. The problem with doing it this way is that unsafePerformIO apparently stops every other thread from doing anything while it is waiting for a packet.
But I can't think of a way to rewrite this function to do what I want. I'm kind of new to this, does anyone have any hints that could help me out?
Here's a simple version without any of the implementation details:
fetchLine = do let results = (unstrict . repeat) getLine mapM_ putStrLn results where unstrict [] = [] unstrict (x:xs) = unsafePerformIO x:unstrict xs
_______________________________________________ Beginners mailing list Beginners@haskell.org http://www.haskell.org/mailman/listinfo/beginners
_______________________________________________ Beginners mailing list Beginners@haskell.org http://www.haskell.org/mailman/listinfo/beginners

How about unsafeInterleaveIO? - You might have to experiment where to put it, but you shouldn't need the local unstrict definition. Because it doesn't violate type safety it is considered less heinous than unsafePerformIO.

I tried this:
fetchUDPSIP :: TChan a -> TChan B.ByteString -> IO ()
fetchUDPSIP commands chan = do
sock <- getUDPSocket 5060
results <- (mapM unsafeInterleaveIO . repeat . getUDP) sock
mapM_ (atomically . writeTChan chan) results
fetchLine = do
results <- (mapM unsafeInterleaveIO . repeat) Prelude.getLine
mapM_ Prelude.putStrLn results
But it seems to have become strict again in that neither version will return
any results until it has gotten everything it can.
Also I'm not sure, but I'm pretty sure any "unsafe" function is still going
to have the original problem where it causes all other threads to stop while
it performs, so I don't think I can use unsafe anything at all and have my
program work properly.
On Mon, Jul 19, 2010 at 10:41 AM, Stephen Tetley
How about unsafeInterleaveIO? - You might have to experiment where to put it, but you shouldn't need the local unstrict definition.
Because it doesn't violate type safety it is considered less heinous than unsafePerformIO. _______________________________________________ Beginners mailing list Beginners@haskell.org http://www.haskell.org/mailman/listinfo/beginners

Okay, I figured this out on my own. This isn't as elegant but it definitely
works:
fetchUDPSIP :: TChan a -> TChan B.ByteString -> IO ()
fetchUDPSIP commands chan = do
sock <- getUDPSocket 5060
loop sock
where
loop sock = do
result <- getUDP sock
(atomically . writeTChan chan) result
loop sock
fetchLine = do
loop
where
loop = do
result <- Prelude.getLine
Prelude.putStrLn result
loop
On Mon, Jul 19, 2010 at 11:09 AM, David McBride
I tried this:
fetchUDPSIP :: TChan a -> TChan B.ByteString -> IO () fetchUDPSIP commands chan = do sock <- getUDPSocket 5060 results <- (mapM unsafeInterleaveIO . repeat . getUDP) sock
mapM_ (atomically . writeTChan chan) results
fetchLine = do results <- (mapM unsafeInterleaveIO . repeat) Prelude.getLine mapM_ Prelude.putStrLn results
But it seems to have become strict again in that neither version will return any results until it has gotten everything it can.
Also I'm not sure, but I'm pretty sure any "unsafe" function is still going to have the original problem where it causes all other threads to stop while it performs, so I don't think I can use unsafe anything at all and have my program work properly.
On Mon, Jul 19, 2010 at 10:41 AM, Stephen Tetley
wrote:
How about unsafeInterleaveIO? - You might have to experiment where to put it, but you shouldn't need the local unstrict definition.
Because it doesn't violate type safety it is considered less heinous than unsafePerformIO. _______________________________________________ Beginners mailing list Beginners@haskell.org http://www.haskell.org/mailman/listinfo/beginners

On Mon, Jul 19, 2010 at 11:18:28AM -0400, David McBride wrote:
Okay, I figured this out on my own. This isn't as elegant but it definitely works:
By the way, your code can be simplified using forever; these ought to be equivalent:
fetchUDPSIP :: TChan a -> TChan B.ByteString -> IO () fetchUDPSIP commands chan = do sock <- getUDPSocket 5060 forever $ do result <- getUDP sock (atomically . writeTChan chan) result
fetchLine = forever $ do result <- Prelude.getLine Prelude.putStrLn result
-Brent

Have you looked at the Real World Haskell example [1] for reading from
a UDP socket? In the inner "procMessages" the authors seem to show
how to read one packet at a time without using unsafePerformIO.
-deech
[1] http://book.realworldhaskell.org/read/sockets-and-syslog.html in
the section marked "UDP Syslog Server"
On Mon, Jul 19, 2010 at 9:07 AM, David McBride
I am writing a voip server to take advantage of haskells awesome threading and parsing ability. At first everything was going great, but my thread that fetches udp makes use of unsafePerformIO:
fetchUDPSIP :: TChan B.ByteString -> IO () fetchUDPSIP chan = do sock <- getUDPSocket 5060 let results = (unstrict . repeat . getUDP) sock mapM_ (atomically . writeTChan chan) results where unstrict [] = [] unstrict (x:xs) = unsafePerformIO x:unstrict xs
It fetches it from a socket, and then writes it to a TChan. This results in a stream of bytestrings that another thread can read from. If I don't use unsafePerformIO, then it tries to read all possible packets before returning anything, and so it never writes to the TChan at all. The problem with doing it this way is that unsafePerformIO apparently stops every other thread from doing anything while it is waiting for a packet.
But I can't think of a way to rewrite this function to do what I want. I'm kind of new to this, does anyone have any hints that could help me out?
Here's a simple version without any of the implementation details:
fetchLine = do let results = (unstrict . repeat) getLine mapM_ putStrLn results where unstrict [] = [] unstrict (x:xs) = unsafePerformIO x:unstrict xs
_______________________________________________ Beginners mailing list Beginners@haskell.org http://www.haskell.org/mailman/listinfo/beginners

Yeah I ended up doing pretty much what they do. The problem was I thought I
could collect all the IO actions one by one into an array and then just map
some other IO action over the array, but apparently the IO monad doesn't
like being lazy.
What you end up having to do is do one IO action at a time, getting the udp,
then sending it over the tchan immediately before attempting to fetch the
next udp packet. I ended up with:
fetchUDPSIP :: TChan a -> TChan B.ByteString -> IO ()
fetchUDPSIP commands chan = do
sock <- getUDPSocket 5060
forever $ getUDP sock >>= atomically . writeTChan chan
Which is perfectly fine. Thanks.
On Mon, Jul 19, 2010 at 1:50 PM, aditya siram
Have you looked at the Real World Haskell example [1] for reading from a UDP socket? In the inner "procMessages" the authors seem to show how to read one packet at a time without using unsafePerformIO.
-deech
[1] http://book.realworldhaskell.org/read/sockets-and-syslog.html in the section marked "UDP Syslog Server"
I am writing a voip server to take advantage of haskells awesome
On Mon, Jul 19, 2010 at 9:07 AM, David McBride
wrote: threading and parsing ability. At first everything was going great, but my thread that fetches udp makes use of unsafePerformIO:
fetchUDPSIP :: TChan B.ByteString -> IO () fetchUDPSIP chan = do sock <- getUDPSocket 5060 let results = (unstrict . repeat . getUDP) sock mapM_ (atomically . writeTChan chan) results where unstrict [] = [] unstrict (x:xs) = unsafePerformIO x:unstrict xs
It fetches it from a socket, and then writes it to a TChan. This results in a stream of bytestrings that another thread can read from. If I don't use unsafePerformIO, then it tries to read all possible packets before returning anything, and so it never writes to the TChan at all. The problem with doing it this way is that unsafePerformIO apparently stops every other thread from doing anything while it is waiting for a packet.
But I can't think of a way to rewrite this function to do what I want. I'm kind of new to this, does anyone have any hints that could help me out?
Here's a simple version without any of the implementation details:
fetchLine = do let results = (unstrict . repeat) getLine mapM_ putStrLn results where unstrict [] = [] unstrict (x:xs) = unsafePerformIO x:unstrict xs
_______________________________________________ Beginners mailing list Beginners@haskell.org http://www.haskell.org/mailman/listinfo/beginners
participants (5)
-
aditya siram
-
Benjamin Edwards
-
Brent Yorgey
-
David McBride
-
Stephen Tetley