Question about the composing order of conduit combination operations

Hi, I'm implementing a tiny SMTP server using conduit-0.4.0 and network-conduit-0.4.0. I wrote code like below:
smtpServer src sink = do LC.sourceList [ renderReply $ SMTPReply 220 (Just "localhost") ["hello"]] $$ sink src $$ C.sequence (sinkParser smtpCommand) =$ LC.map (BS.pack . show) =$ sink
Here is the complete (and slightly different) code: https://github.com/konn/haskell-smtp/blob/master/smtp-server/Network/SMTP/Se... (You know, this server is not actually an smtp server; just echoing client's input for now.) I ran this program and communicated using telnet. I expected the access log like below (S means server, C means client; new-lines are CRLF) :
S: 220 localhost hello C: EHLO another.example.com S: EHLO "another.example.com" C: MAIL FROM:
S: MAIL (Path [] (Mailbox {mbLocalPart = "Postmaster", mbDomain = "example.com"})) [] C: RCPT TO: S: RCPT (Path [] (Mailbox {mbLocalPart = "foo", mbDomain = "example.com"})) [] C: DATA C: hoge C: fuga C: oooo C: . S: DATA "hoge\r\nfuga\r\noooo" C: QUIT S: QUIT
But I got:
S: 220 localhost hello C: EHLO another.example.com C: MAIL FROM:
C: RCPT TO: S: EHLO "another.example.com" C: DATA S: MAIL (Path [] (Mailbox {mbLocalPart = "Postmaster", mbDomain = "example.com"})) [] C: hoge C: fuga C: oooo C: . C: QUIT S: RCPT (Path [] (Mailbox {mbLocalPart = "foo", mbDomain = "example.com"})) []
It seems that conduit produces a new SMTPCommand after reading another new command, and processes and convert it into SMTPReply much father later. By the way, I rewrote the program above just like below and everythings seems to be good:
smtpServer src sink = do LC.sourceList [ renderReply $ SMTPReply 220 (Just "localhost") ["hello"]] $$ sink src $= C.sequence (sinkParser smtpCommand) $= LC.map (BS.pack . show) $$ sink
If Conduits, Sinks and Sources are the same sings in conduit-0.4, why these two codes above behaves differently? To summarize, my questions are divided into three: 1. Why the first one doesn't work as I expected? 2. Why the second one works well? 3. Is this difference intended? If so, what are the difference of semantics of ($=), (=$), ($$), (=$=) and their composition? -- Hiromi ISHII konn.jinro@gmail.com

I'm not sure of the details of the question, but there was a bug in
conduit 0.4.0 that I fixed in 0.4.0.1. It affected the order of
operations in cases like this. I believe the exact issue was that it
would perform monadic actions from the left-hand-side even if output
wasn't needed yet.
Can you try upgrading and see if that solves your problem?
Michael
On Thu, Apr 5, 2012 at 3:01 PM, Hiromi ISHII
Hi,
I'm implementing a tiny SMTP server using conduit-0.4.0 and network-conduit-0.4.0.
I wrote code like below:
smtpServer src sink = do LC.sourceList [ renderReply $ SMTPReply 220 (Just "localhost") ["hello"]] $$ sink src $$ C.sequence (sinkParser smtpCommand) =$ LC.map (BS.pack . show) =$ sink
Here is the complete (and slightly different) code: https://github.com/konn/haskell-smtp/blob/master/smtp-server/Network/SMTP/Se... (You know, this server is not actually an smtp server; just echoing client's input for now.)
I ran this program and communicated using telnet. I expected the access log like below (S means server, C means client; new-lines are CRLF) :
S: 220 localhost hello C: EHLO another.example.com S: EHLO "another.example.com" C: MAIL FROM:
S: MAIL (Path [] (Mailbox {mbLocalPart = "Postmaster", mbDomain = "example.com"})) [] C: RCPT TO: S: RCPT (Path [] (Mailbox {mbLocalPart = "foo", mbDomain = "example.com"})) [] C: DATA C: hoge C: fuga C: oooo C: . S: DATA "hoge\r\nfuga\r\noooo" C: QUIT S: QUIT But I got:
S: 220 localhost hello C: EHLO another.example.com C: MAIL FROM:
C: RCPT TO: S: EHLO "another.example.com" C: DATA S: MAIL (Path [] (Mailbox {mbLocalPart = "Postmaster", mbDomain = "example.com"})) [] C: hoge C: fuga C: oooo C: . C: QUIT S: RCPT (Path [] (Mailbox {mbLocalPart = "foo", mbDomain = "example.com"})) [] It seems that conduit produces a new SMTPCommand after reading another new command, and processes and convert it into SMTPReply much father later.
By the way, I rewrote the program above just like below and everythings seems to be good:
smtpServer src sink = do LC.sourceList [ renderReply $ SMTPReply 220 (Just "localhost") ["hello"]] $$ sink src $= C.sequence (sinkParser smtpCommand) $= LC.map (BS.pack . show) $$ sink
If Conduits, Sinks and Sources are the same sings in conduit-0.4, why these two codes above behaves differently? To summarize, my questions are divided into three:
1. Why the first one doesn't work as I expected? 2. Why the second one works well? 3. Is this difference intended? If so, what are the difference of semantics of ($=), (=$), ($$), (=$=) and their composition?
-- Hiromi ISHII konn.jinro@gmail.com
_______________________________________________ web-devel mailing list web-devel@haskell.org http://www.haskell.org/mailman/listinfo/web-devel
participants (2)
-
Hiromi ISHII
-
Michael Snoyman