Send Beginners mailing list submissions to
[email protected]
To subscribe or unsubscribe via the World Wide Web, visit
http://www.haskell.org/mailman/listinfo/beginners
or, via email, send a message with subject or body 'help' to
[email protected]
You can reach the person managing the list at
[email protected]
When replying, please edit your Subject line so it is more specific
than "Re: Contents of Beginners digest..."
Today's Topics:
1. Implementing a toy network proxy (Patrick LeBoutillier)
2. Re: Implementing a toy network proxy (Michael Snoyman)
3. generating arbitrary parameter lists (Amy de Buitl?ir)
4. Re: Implementing a toy network proxy (Patrick LeBoutillier)
5. Re: Implementing a toy network proxy (Michael Snoyman)
6. Re: generating arbitrary parameter lists (Edward Z. Yang)
7. Re: generating arbitrary parameter lists (Amy de Buitl?ir)
----------------------------------------------------------------------
Message: 1
Date: Thu, 23 Sep 2010 13:13:53 -0400
From: Patrick LeBoutillier <[email protected]>
Subject: [Haskell-beginners] Implementing a toy network proxy
To: beginners <[email protected]>
Message-ID:
<[email protected]>
Content-Type: text/plain; charset=ISO-8859-1
Hi ,
I'm trying to write a toy generic network proxy that will accept
connections on a port, and for each connection connect
to a remote server and forward the traffic.
Here's what I have do far:
import Network
import System.IO
import Control.Exception
import Control.Concurrent
copy :: Handle -> Handle -> IO ()
copy a b = undefined
redir :: Handle -> Handle -> IO ()
redir h1 h2 = forkIO (copy h1 h2) >> forkIO (copy h2 h1) >> return ()
acceptLoop :: Socket -> HostName -> PortID -> IO ()
acceptLoop sock rhost rport = loop
where loop = do
(local, host, port) <- accept sock
remote <- connectTo rhost rport
redir local remote
loop >> return ()
main = do
let local_port = 8000
let remote_host = "whatever"
let remote_port = 80
server <- listenOn (PortNumber local_port)
acceptLoop server remote_host (PortNumber remote_port)
Basically I'm stuck at how to implement the copy function. I want it
to block until some data is available on a,
read it and then write it to b.
I think I need to use hGetBufNonBlocking, but I don't know how to get a "Ptr a".
I am on the right track with this?
Patrick
--
=====================
Patrick LeBoutillier
Rosemère, Québec, Canada
------------------------------
Message: 2
Date: Thu, 23 Sep 2010 19:26:06 +0200
From: Michael Snoyman <[email protected]>
Subject: Re: [Haskell-beginners] Implementing a toy network proxy
To: Patrick LeBoutillier <[email protected]>
Cc: beginners <[email protected]>
Message-ID:
<[email protected]>
Content-Type: text/plain; charset=ISO-8859-1
It might be easier to use bytestrings instead of Ptr (). I think the
relevant function is hGetNonBlocking[1].
Cheers,
Michael
[1]
http://hackage.haskell.org/packages/archive/bytestring/0.9.1.7/doc/html/Data-ByteString.html#v:hGetNonBlocking
On Thu, Sep 23, 2010 at 7:13 PM, Patrick LeBoutillier
<[email protected]> wrote:
> Hi ,
>
> I'm trying to write a toy generic network proxy that will accept
> connections on a port, and for each connection connect
> to a remote server and forward the traffic.
>
>
> Here's what I have do far:
>
>
> import Network
> import System.IO
> import Control.Exception
> import Control.Concurrent
>
>
> copy :: Handle -> Handle -> IO ()
> copy a b = undefined
>
>
> redir :: Handle -> Handle -> IO ()
> redir h1 h2 = forkIO (copy h1 h2) >> forkIO (copy h2 h1) >> return ()
>
>
> acceptLoop :: Socket -> HostName -> PortID -> IO ()
> acceptLoop sock rhost rport = loop
> where loop = do
> (local, host, port) <- accept sock
> remote <- connectTo rhost rport
> redir local remote
> loop >> return ()
>
>
> main = do
> let local_port = 8000
> let remote_host = "whatever"
> let remote_port = 80
> server <- listenOn (PortNumber local_port)
> acceptLoop server remote_host (PortNumber remote_port)
>
>
>
> Basically I'm stuck at how to implement the copy function. I want it
> to block until some data is available on a,
> read it and then write it to b.
>
> I think I need to use hGetBufNonBlocking, but I don't know how to get a "Ptr
> a".
>
> I am on the right track with this?
>
>
> Patrick
> --
> =====================
> Patrick LeBoutillier
> Rosemère, Québec, Canada
> _______________________________________________
> Beginners mailing list
> [email protected]
> http://www.haskell.org/mailman/listinfo/beginners
>
------------------------------
Message: 3
Date: Thu, 23 Sep 2010 22:56:39 +0100
From: Amy de Buitl?ir <[email protected]>
Subject: [Haskell-beginners] generating arbitrary parameter lists
To: beginners <[email protected]>
Message-ID:
<[email protected]>
Content-Type: text/plain; charset=ISO-8859-1
Whenever I want to use quickCheck to test some function with multiple
input parameters, I end up writing boilerplate code that looks like
the example below. I have a feeling I'm missing out on some good
Haskell tricks. In particular, writing a function like arbXYZ for
every combination of parameter types that I need to test is a bit
repetitive. Is there a better way?
Thank you in advance,
Amy
----- code example -----
functionIWantToTest :: Double -> Int -> Bool -> Double
functionIWantToTest x y z = 27 -- pretend we're doing something useful
arbXYZ :: Gen (Double, Int, Bool)
arbXYZ = do
x <- choose (0.0, 1.0)
y <- choose (1, 10)
z <- arbitrary
return (x, y, z)
conditionIWantToCheck :: (Double, Int, Bool) -> Bool
conditionIWantToCheck (x, y, z) = True -- pretend we're checking something
prop_i_want_to_check :: Property
prop_i_want_to_check = forAll arbXYZ conditionIWantToCheck
------------------------------
Message: 4
Date: Thu, 23 Sep 2010 19:18:11 -0400
From: Patrick LeBoutillier <[email protected]>
Subject: Re: [Haskell-beginners] Implementing a toy network proxy
To: Michael Snoyman <[email protected]>
Cc: beginners <[email protected]>
Message-ID:
<[email protected]>
Content-Type: text/plain; charset=ISO-8859-1
Ok, finally I wound up with this:
import Network
import System.IO
import Control.Concurrent
import IO (hWaitForInput)
import System.IO.Error (try)
import qualified Data.ByteString as B
copy :: Handle -> Handle -> IO ()
copy a b = do
r <- try $ hWaitForInput a (-1)
buf <- case r of
Right _ -> B.hGetNonBlocking a 4096
Left err -> return B.empty
if B.null buf
then hClose a >> hClose b
else B.hPut b buf >> copy a b
main = do
let lport = 8000
let rhost = "idefix"
let rport = 80
listenOn (PortNumber lport) >>= acceptLoop rhost rport
where
acceptLoop rhost rport server = do
(local, _, _) <- accept server
hSetBuffering local NoBuffering
forkIO $ do
remote <- connectTo rhost (PortNumber rport)
hSetBuffering remote NoBuffering
redir local remote
acceptLoop rhost rport server
redir h1 h2 = forkIO (copy h1 h2) >> forkIO (copy h2 h1)
That seems to do the job, but it feels a bit clunky when I do a manual
telnet through it.
Do I have to compile/run it in a special way to make the forkIOs
really parallelize?
It also feels like the hCloses are not happening immediately. Is there
anything I can do about that?
Thanks a lot,
Patrick
On Thu, Sep 23, 2010 at 1:26 PM, Michael Snoyman <[email protected]> wrote:
> It might be easier to use bytestrings instead of Ptr (). I think the
> relevant function is hGetNonBlocking[1].
>
> Cheers,
> Michael
>
> [1]
> http://hackage.haskell.org/packages/archive/bytestring/0.9.1.7/doc/html/Data-ByteString.html#v:hGetNonBlocking
>
> On Thu, Sep 23, 2010 at 7:13 PM, Patrick LeBoutillier
> <[email protected]> wrote:
>> Hi ,
>>
>> I'm trying to write a toy generic network proxy that will accept
>> connections on a port, and for each connection connect
>> to a remote server and forward the traffic.
>>
>>
>> Here's what I have do far:
>>
>>
>> import Network
>> import System.IO
>> import Control.Exception
>> import Control.Concurrent
>>
>>
>> copy :: Handle -> Handle -> IO ()
>> copy a b = undefined
>>
>>
>> redir :: Handle -> Handle -> IO ()
>> redir h1 h2 = forkIO (copy h1 h2) >> forkIO (copy h2 h1) >> return ()
>>
>>
>> acceptLoop :: Socket -> HostName -> PortID -> IO ()
>> acceptLoop sock rhost rport = loop
>> where loop = do
>> (local, host, port) <- accept sock
>> remote <- connectTo rhost rport
>> redir local remote
>> loop >> return ()
>>
>>
>> main = do
>> let local_port = 8000
>> let remote_host = "whatever"
>> let remote_port = 80
>> server <- listenOn (PortNumber local_port)
>> acceptLoop server remote_host (PortNumber remote_port)
>>
>>
>>
>> Basically I'm stuck at how to implement the copy function. I want it
>> to block until some data is available on a,
>> read it and then write it to b.
>>
>> I think I need to use hGetBufNonBlocking, but I don't know how to get a "Ptr
>> a".
>>
>> I am on the right track with this?
>>
>>
>> Patrick
>> --
>> =====================
>> Patrick LeBoutillier
>> Rosemère, Québec, Canada
>> _______________________________________________
>> Beginners mailing list
>> [email protected]
>> http://www.haskell.org/mailman/listinfo/beginners
>>
>
--
=====================
Patrick LeBoutillier
Rosemère, Québec, Canada
------------------------------
Message: 5
Date: Fri, 24 Sep 2010 02:33:56 +0200
From: Michael Snoyman <[email protected]>
Subject: Re: [Haskell-beginners] Implementing a toy network proxy
To: Patrick LeBoutillier <[email protected]>
Cc: beginners <[email protected]>
Message-ID:
<[email protected]>
Content-Type: text/plain; charset=ISO-8859-1
I just tried the code on my system; worked great for an SSH session.
Maybe you want to try with the multithreaded runtime, ie:
ghc --make -threaded filename.hs
On Fri, Sep 24, 2010 at 1:18 AM, Patrick LeBoutillier
<[email protected]> wrote:
> Ok, finally I wound up with this:
>
> import Network
> import System.IO
> import Control.Concurrent
> import IO (hWaitForInput)
> import System.IO.Error (try)
> import qualified Data.ByteString as B
>
>
> copy :: Handle -> Handle -> IO ()
> copy a b = do
> r <- try $ hWaitForInput a (-1)
> buf <- case r of
> Right _ -> B.hGetNonBlocking a 4096
> Left err -> return B.empty
> if B.null buf
> then hClose a >> hClose b
> else B.hPut b buf >> copy a b
>
>
> main = do
> let lport = 8000
> let rhost = "idefix"
> let rport = 80
>
> listenOn (PortNumber lport) >>= acceptLoop rhost rport
>
> where
> acceptLoop rhost rport server = do
> (local, _, _) <- accept server
> hSetBuffering local NoBuffering
> forkIO $ do
> remote <- connectTo rhost (PortNumber rport)
> hSetBuffering remote NoBuffering
> redir local remote
> acceptLoop rhost rport server
>
> redir h1 h2 = forkIO (copy h1 h2) >> forkIO (copy h2 h1)
>
>
> That seems to do the job, but it feels a bit clunky when I do a manual
> telnet through it.
> Do I have to compile/run it in a special way to make the forkIOs
> really parallelize?
>
> It also feels like the hCloses are not happening immediately. Is there
> anything I can do about that?
>
>
> Thanks a lot,
>
> Patrick
>
>
>
> On Thu, Sep 23, 2010 at 1:26 PM, Michael Snoyman <[email protected]> wrote:
>> It might be easier to use bytestrings instead of Ptr (). I think the
>> relevant function is hGetNonBlocking[1].
>>
>> Cheers,
>> Michael
>>
>> [1]
>> http://hackage.haskell.org/packages/archive/bytestring/0.9.1.7/doc/html/Data-ByteString.html#v:hGetNonBlocking
>>
>> On Thu, Sep 23, 2010 at 7:13 PM, Patrick LeBoutillier
>> <[email protected]> wrote:
>>> Hi ,
>>>
>>> I'm trying to write a toy generic network proxy that will accept
>>> connections on a port, and for each connection connect
>>> to a remote server and forward the traffic.
>>>
>>>
>>> Here's what I have do far:
>>>
>>>
>>> import Network
>>> import System.IO
>>> import Control.Exception
>>> import Control.Concurrent
>>>
>>>
>>> copy :: Handle -> Handle -> IO ()
>>> copy a b = undefined
>>>
>>>
>>> redir :: Handle -> Handle -> IO ()
>>> redir h1 h2 = forkIO (copy h1 h2) >> forkIO (copy h2 h1) >> return ()
>>>
>>>
>>> acceptLoop :: Socket -> HostName -> PortID -> IO ()
>>> acceptLoop sock rhost rport = loop
>>> where loop = do
>>> (local, host, port) <- accept sock
>>> remote <- connectTo rhost rport
>>> redir local remote
>>> loop >> return ()
>>>
>>>
>>> main = do
>>> let local_port = 8000
>>> let remote_host = "whatever"
>>> let remote_port = 80
>>> server <- listenOn (PortNumber local_port)
>>> acceptLoop server remote_host (PortNumber remote_port)
>>>
>>>
>>>
>>> Basically I'm stuck at how to implement the copy function. I want it
>>> to block until some data is available on a,
>>> read it and then write it to b.
>>>
>>> I think I need to use hGetBufNonBlocking, but I don't know how to get a
>>> "Ptr a".
>>>
>>> I am on the right track with this?
>>>
>>>
>>> Patrick
>>> --
>>> =====================
>>> Patrick LeBoutillier
>>> Rosemère, Québec, Canada
>>> _______________________________________________
>>> Beginners mailing list
>>> [email protected]
>>> http://www.haskell.org/mailman/listinfo/beginners
>>>
>>
>
>
>
> --
> =====================
> Patrick LeBoutillier
> Rosemère, Québec, Canada
>
------------------------------
Message: 6
Date: Thu, 23 Sep 2010 23:57:19 -0400
From: "Edward Z. Yang" <[email protected]>
Subject: Re: [Haskell-beginners] generating arbitrary parameter lists
To: Amy de Buitl?ir <[email protected]>
Cc: beginners <[email protected]>
Message-ID: <1285300447-sup-2...@ezyang>
Content-Type: text/plain; charset=UTF-8
Hello Andy,
Gen is a funny typeclass, in particular I can write something like:
prop_foo x y z = {- do something with x y z -}
and QuickCheck will automatically fill in x, y, z using arbitrary from
the inferred type classes. This will work fine for z but no so much
for x and y in your example, in which case you can create newtypes
that encodes things like [bounded from 0.0 to 1.0], etc.
I often find hanging lambda style with forAll to be quite palatable,
so I frequently find myself writing things like:
conditionIWantToCheck z =
forAll (choose (0.0, 1.0)) $ \x ->
forAll (choose (1, 10)) $ \y ->
{- condition -}
Especially when the inner forAlls have dependencies on earlier forAlls,
this style is quite natural.
Cheers,
Edward
Excerpts from Amy de Buitléir's message of Thu Sep 23 17:56:39 -0400 2010:
> Whenever I want to use quickCheck to test some function with multiple
> input parameters, I end up writing boilerplate code that looks like
> the example below. I have a feeling I'm missing out on some good
> Haskell tricks. In particular, writing a function like arbXYZ for
> every combination of parameter types that I need to test is a bit
> repetitive. Is there a better way?
>
> Thank you in advance,
> Amy
>
> ----- code example -----
>
> functionIWantToTest :: Double -> Int -> Bool -> Double
> functionIWantToTest x y z = 27 -- pretend we're doing something useful
>
> arbXYZ :: Gen (Double, Int, Bool)
> arbXYZ = do
> x <- choose (0.0, 1.0)
> y <- choose (1, 10)
> z <- arbitrary
> return (x, y, z)
>
> conditionIWantToCheck :: (Double, Int, Bool) -> Bool
> conditionIWantToCheck (x, y, z) = True -- pretend we're checking something
>
> prop_i_want_to_check :: Property
> prop_i_want_to_check = forAll arbXYZ conditionIWantToCheck
------------------------------
Message: 7
Date: Fri, 24 Sep 2010 17:33:57 +0100
From: Amy de Buitl?ir <[email protected]>
Subject: Re: [Haskell-beginners] generating arbitrary parameter lists
To: "Edward Z. Yang" <[email protected]>
Cc: beginners <[email protected]>
Message-ID:
<[email protected]>
Content-Type: text/plain; charset=ISO-8859-1
Thank you, Edward. That hanging lambda style looks particularly useful
for my purposes.
------------------------------
_______________________________________________
Beginners mailing list
[email protected]
http://www.haskell.org/mailman/listinfo/beginners
End of Beginners Digest, Vol 27, Issue 52
*****************************************