<div dir="ltr"><div class="markdown-here-wrapper" style=""><p style="margin:0px 0px 1.2em!important">Hi Haskellers,</p>
<p style="margin:0px 0px 1.2em!important">I just rewrote the code to a state-machine in the hope that I can eventually collapse several stages in a pipeline into one, but this simple state-machine version turns out to be about 3 times slower even though it does the same thing:</p>
<pre style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;font-size:1em;line-height:1.2em;margin:1.2em 0px"><code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:pre-wrap;border:1px solid rgb(234,234,234);border-radius:3px;display:inline;background-color:rgb(248,248,248);white-space:pre;overflow:auto;border-radius:3px;border:1px solid rgb(204,204,204);padding:0.5em 0.7em;display:block!important">newtype Blank = Blank
  { blank :: BS.ByteString -> Maybe (Word8, (BS.ByteString, Blank))
  }

escapeChar :: BS.ByteString -> Maybe (Word8, (BS.ByteString, Blank))
escapeChar bs = case BS.uncons bs of
  Just (c, cs)  -> Just (c, (cs, Blank (if c /= wBackslash then escapeChar else escapedChar)))
  Nothing       -> Nothing

escapedChar :: BS.ByteString -> Maybe (Word8, (BS.ByteString, Blank))
escapedChar bs = case BS.uncons bs of
  Just (_, cs) -> Just (wUnderscore, (cs, Blank escapeChar))
  Nothing      -> Nothing

fastBlank :: MonadThrow m => Conduit BS.ByteString m BS.ByteString
fastBlank = fastBlank' escapeChar

fastBlank' :: MonadThrow m => (BS.ByteString -> Maybe (Word8, (BS.ByteString, Blank))) -> Conduit BS.ByteString m BS.ByteString
fastBlank' blank = do
  mbs <- await
  case mbs of
    Just bs -> do
      let (cs, Just (_, Blank newBlank)) = unfoldrN (BS.length bs) (\(bs, Blank f) -> f bs) (bs, Blank blank)
      yield cs
      fastBlank' newBlank
    Nothing -> return ()
</code></pre><p style="margin:0px 0px 1.2em!important">I worry that if I go this approach, just the cost of the state-machine might mean I only break-even.</p>
<p style="margin:0px 0px 1.2em!important">Is there any reason why this version should be slower?</p>
<p style="margin:0px 0px 1.2em!important">Cheers,</p>
<p style="margin:0px 0px 1.2em!important">-John</p>
<div title="MDH:SGkgSGFza2VsbGVycyw8ZGl2Pjxicj48L2Rpdj48ZGl2PkkganVzdCByZXdyb3RlIHRoZSBjb2Rl
IHRvIGEgc3RhdGUtbWFjaGluZSBpbiB0aGUgaG9wZSB0aGF0IEkgY2FuIGV2ZW50dWFsbHkgY29s
bGFwc2Ugc2V2ZXJhbCBzdGFnZXMgaW4gYSBwaXBlbGluZSBpbnRvIG9uZSwgYnV0IHRoaXMgc2lt
cGxlIHN0YXRlLW1hY2hpbmUgdmVyc2lvbiB0dXJucyBvdXQgdG8gYmUgYWJvdXQgMyB0aW1lcyBz
bG93ZXI6PC9kaXY+PGRpdj48YnI+PC9kaXY+PGRpdj5gYGA8YnI+PGRpdj5uZXd0eXBlIEJsYW5r
ID0gQmxhbms8L2Rpdj48ZGl2PiZuYnNwOyB7IGJsYW5rIDo6IEJTLkJ5dGVTdHJpbmcgLSZndDsg
TWF5YmUgKFdvcmQ4LCAoQlMuQnl0ZVN0cmluZywgQmxhbmspKTwvZGl2PjxkaXY+Jm5ic3A7IH08
L2Rpdj48ZGl2Pjxicj48L2Rpdj48ZGl2PmVzY2FwZUNoYXIgOjogQlMuQnl0ZVN0cmluZyAtJmd0
OyBNYXliZSAoV29yZDgsIChCUy5CeXRlU3RyaW5nLCBCbGFuaykpPC9kaXY+PGRpdj5lc2NhcGVD
aGFyIGJzID0gY2FzZSBCUy51bmNvbnMgYnMgb2Y8L2Rpdj48ZGl2PiZuYnNwOyBKdXN0IChjLCBj
cykgJm5ic3A7LSZndDsgSnVzdCAoYywgKGNzLCBCbGFuayAoaWYgYyAvPSB3QmFja3NsYXNoIHRo
ZW4gZXNjYXBlQ2hhciBlbHNlIGVzY2FwZWRDaGFyKSkpPC9kaXY+PGRpdj4mbmJzcDsgTm90aGlu
ZyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAtJmd0OyBOb3RoaW5nPC9kaXY+PGRpdj48YnI+PC9kaXY+
PGRpdj5lc2NhcGVkQ2hhciA6OiBCUy5CeXRlU3RyaW5nIC0mZ3Q7IE1heWJlIChXb3JkOCwgKEJT
LkJ5dGVTdHJpbmcsIEJsYW5rKSk8L2Rpdj48ZGl2PmVzY2FwZWRDaGFyIGJzID0gY2FzZSBCUy51
bmNvbnMgYnMgb2Y8L2Rpdj48ZGl2PiZuYnNwOyBKdXN0IChfLCBjcykgLSZndDsgSnVzdCAod1Vu
ZGVyc2NvcmUsIChjcywgQmxhbmsgZXNjYXBlQ2hhcikpPC9kaXY+PGRpdj4mbmJzcDsgTm90aGlu
ZyAmbmJzcDsgJm5ic3A7ICZuYnNwOy0mZ3Q7IE5vdGhpbmc8L2Rpdj48ZGl2Pjxicj48L2Rpdj48
ZGl2PmZhc3RCbGFuayA6OiBNb25hZFRocm93IG0gPSZndDsgQ29uZHVpdCBCUy5CeXRlU3RyaW5n
IG0gQlMuQnl0ZVN0cmluZzwvZGl2PjxkaXY+ZmFzdEJsYW5rID0gZmFzdEJsYW5rJyBlc2NhcGVD
aGFyPC9kaXY+PGRpdj48YnI+PC9kaXY+PGRpdj5mYXN0QmxhbmsnIDo6IE1vbmFkVGhyb3cgbSA9
Jmd0OyAoQlMuQnl0ZVN0cmluZyAtJmd0OyBNYXliZSAoV29yZDgsIChCUy5CeXRlU3RyaW5nLCBC
bGFuaykpKSAtJmd0OyBDb25kdWl0IEJTLkJ5dGVTdHJpbmcgbSBCUy5CeXRlU3RyaW5nPC9kaXY+
PGRpdj5mYXN0QmxhbmsnIGJsYW5rID0gZG88L2Rpdj48ZGl2PiZuYnNwOyBtYnMgJmx0Oy0gYXdh
aXQ8L2Rpdj48ZGl2PiZuYnNwOyBjYXNlIG1icyBvZjwvZGl2PjxkaXY+Jm5ic3A7ICZuYnNwOyBK
dXN0IGJzIC0mZ3Q7IGRvPC9kaXY+PGRpdj4mbmJzcDsgJm5ic3A7ICZuYnNwOyBsZXQgKGNzLCBK
dXN0IChfLCBCbGFuayBuZXdCbGFuaykpID0gdW5mb2xkck4gKEJTLmxlbmd0aCBicykgKFwoYnMs
IEJsYW5rIGYpIC0mZ3Q7IGYgYnMpIChicywgQmxhbmsgYmxhbmspPC9kaXY+PGRpdj4mbmJzcDsg
Jm5ic3A7ICZuYnNwOyB5aWVsZCBjczwvZGl2PjxkaXY+Jm5ic3A7ICZuYnNwOyAmbmJzcDsgZmFz
dEJsYW5rJyBuZXdCbGFuazwvZGl2PjxkaXY+Jm5ic3A7ICZuYnNwOyBOb3RoaW5nIC0mZ3Q7IHJl
dHVybiAoKTwvZGl2PjwvZGl2PjxkaXY+YGBgPC9kaXY+PGRpdj48YnI+PC9kaXY+PGRpdj5JIHdv
cnJ5IHRoYXQgaWYgSSBnbyB0aGlzIGFwcHJvYWNoLCBqdXN0IHRoZSBjb3N0IG9mIHRoZSBzdGF0
ZS1tYWNoaW5lIG1pZ2h0IG1lYW4gSSBvbmx5IGJyZWFrLWV2ZW4uPC9kaXY+PGRpdj48YnI+PC9k
aXY+PGRpdj5JcyB0aGVyZSBhbnkgcmVhc29uIHdoeSB0aGlzIHZlcnNpb24gc2hvdWxkIGJlIHNs
b3dlcj88L2Rpdj48ZGl2Pjxicj48L2Rpdj48ZGl2PkNoZWVycyw8L2Rpdj48ZGl2Pjxicj48L2Rp
dj48ZGl2Pi1Kb2huPC9kaXY+PGRpdj48YnI+PC9kaXY+" style="height:0;width:0;max-height:0;max-width:0;overflow:hidden;font-size:0em;padding:0;margin:0">​</div></div><br><div class="gmail_quote"><div dir="ltr">On Sun, 3 Apr 2016 at 23:11 John Ky <<a href="mailto:newhoggy@gmail.com">newhoggy@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div><p style="margin:0px 0px 1.2em!important">Hello Haskellers,</p>
<p style="margin:0px 0px 1.2em!important">I’ve been trying to squeeze as much performance out of my code as possible and I’ve come to a point where can’t figure out what more I can do.</p>
<p style="margin:0px 0px 1.2em!important">Here is some example code:</p>
<pre style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;font-size:1em;line-height:1.2em;margin:1.2em 0px"><code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:pre-wrap;border:1px solid rgb(234,234,234);border-radius:3px;display:inline;background-color:rgb(248,248,248);white-space:pre-wrap;overflow:auto;border-radius:3px;border:1px solid rgb(204,204,204);padding:0.5em 0.7em;display:block!important">blankEscapedChars :: MonadThrow m => Conduit BS.ByteString m BS.ByteString
blankEscapedChars = blankEscapedChars' ""

blankEscapedChars' :: MonadThrow m => BS.ByteString -> Conduit BS.ByteString m BS.ByteString
blankEscapedChars' rs = do
  mbs <- await
  case mbs of
    Just bs -> do
      let cs = if BS.length rs /= 0 then BS.concat [rs, bs] else bs
      let ds = fst (unfoldrN (BS.length cs) unescapeByteString (False, cs))
      yield ds
      blankEscapedChars' (BS.drop (BS.length ds) cs)
    Nothing -> when (BS.length rs > 0) (yield rs)
  where
    unescapeByteString :: (Bool, ByteString) -> Maybe (Word8, (Bool, ByteString))
    unescapeByteString (wasEscaped, bs) = case BS.uncons bs of
      Just (_, cs) | wasEscaped       -> Just (wUnderscore, (False, cs))
      Just (c, cs) | c /= wBackslash  -> Just (c, (False, cs))
      Just (c, cs)                    -> Just (c, (True, cs))
      Nothing                         -> Nothing
</code></pre><p style="margin:0px 0px 1.2em!important">The above function <code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:pre-wrap;border:1px solid rgb(234,234,234);border-radius:3px;display:inline;background-color:rgb(248,248,248)">blankEscapedChars</code> will go find all <code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:pre-wrap;border:1px solid rgb(234,234,234);border-radius:3px;display:inline;background-color:rgb(248,248,248)">\</code> characters and convert the following character to a <code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:pre-wrap;border:1px solid rgb(234,234,234);border-radius:3px;display:inline;background-color:rgb(248,248,248)">_</code>.  For a <code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:pre-wrap;border:1px solid rgb(234,234,234);border-radius:3px;display:inline;background-color:rgb(248,248,248)">1 MB</code> in memory JSON <code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:pre-wrap;border:1px solid rgb(234,234,234);border-radius:3px;display:inline;background-color:rgb(248,248,248)">ByteString</code>, it benches at about <code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:pre-wrap;border:1px solid rgb(234,234,234);border-radius:3px;display:inline;background-color:rgb(248,248,248)">6.6 ms</code></p>
<p style="margin:0px 0px 1.2em!important">In all my code the basic strategy is the same.  <code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:pre-wrap;border:1px solid rgb(234,234,234);border-radius:3px;display:inline;background-color:rgb(248,248,248)">await</code> for the next byte string, then use and <code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:pre-wrap;border:1px solid rgb(234,234,234);border-radius:3px;display:inline;background-color:rgb(248,248,248)">unfoldrN</code> to produce a new <code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:pre-wrap;border:1px solid rgb(234,234,234);border-radius:3px;display:inline;background-color:rgb(248,248,248)">ByteString</code> for yielding.</p>
<p style="margin:0px 0px 1.2em!important">Anyone know of a way to go faster?</p>
<p style="margin:0px 0px 1.2em!important">Cheers,</p>
<p style="margin:0px 0px 1.2em!important">-John</p>
<div title="MDH:SGVsbG8gSGFza2VsbGVycyw8ZGl2Pjxicj48L2Rpdj48ZGl2PkkndmUgYmVlbiB0cnlpbmcgdG8g
c3F1ZWV6ZSBhcyBtdWNoIHBlcmZvcm1hbmNlIG91dCBvZiBteSBjb2RlIGFzIHBvc3NpYmxlIGFu
ZCBJJ3ZlIGNvbWUgdG8gYSBwb2ludCB3aGVyZSBjYW4ndCBmaWd1cmUgb3V0IHdoYXQgbW9yZSBJ
IGNhbiBkby48L2Rpdj48ZGl2Pjxicj48L2Rpdj48ZGl2PkhlcmUgaXMgc29tZSBleGFtcGxlIGNv
ZGU6PC9kaXY+PGRpdj48YnI+PC9kaXY+PGRpdj5gYGA8L2Rpdj48ZGl2PjxkaXY+YmxhbmtFc2Nh
cGVkQ2hhcnMgOjogTW9uYWRUaHJvdyBtID0mZ3Q7IENvbmR1aXQgQlMuQnl0ZVN0cmluZyBtIEJT
LkJ5dGVTdHJpbmc8L2Rpdj48ZGl2PmJsYW5rRXNjYXBlZENoYXJzID0gYmxhbmtFc2NhcGVkQ2hh
cnMnICIiPC9kaXY+PGRpdj48YnI+PC9kaXY+PGRpdj5ibGFua0VzY2FwZWRDaGFycycgOjogTW9u
YWRUaHJvdyBtID0mZ3Q7IEJTLkJ5dGVTdHJpbmcgLSZndDsgQ29uZHVpdCBCUy5CeXRlU3RyaW5n
IG0gQlMuQnl0ZVN0cmluZzwvZGl2PjxkaXY+YmxhbmtFc2NhcGVkQ2hhcnMnIHJzID0gZG88L2Rp
dj48ZGl2PiZuYnNwOyBtYnMgJmx0Oy0gYXdhaXQ8L2Rpdj48ZGl2PiZuYnNwOyBjYXNlIG1icyBv
ZjwvZGl2PjxkaXY+Jm5ic3A7ICZuYnNwOyBKdXN0IGJzIC0mZ3Q7IGRvPC9kaXY+PGRpdj4mbmJz
cDsgJm5ic3A7ICZuYnNwOyBsZXQgY3MgPSBpZiBCUy5sZW5ndGggcnMgLz0gMCB0aGVuIEJTLmNv
bmNhdCBbcnMsIGJzXSBlbHNlIGJzPC9kaXY+PGRpdj4mbmJzcDsgJm5ic3A7ICZuYnNwOyBsZXQg
ZHMgPSBmc3QgKHVuZm9sZHJOIChCUy5sZW5ndGggY3MpIHVuZXNjYXBlQnl0ZVN0cmluZyAoRmFs
c2UsIGNzKSk8L2Rpdj48ZGl2PiZuYnNwOyAmbmJzcDsgJm5ic3A7IHlpZWxkIGRzPC9kaXY+PGRp
dj4mbmJzcDsgJm5ic3A7ICZuYnNwOyBibGFua0VzY2FwZWRDaGFycycgKEJTLmRyb3AgKEJTLmxl
bmd0aCBkcykgY3MpPC9kaXY+PGRpdj4mbmJzcDsgJm5ic3A7IE5vdGhpbmcgLSZndDsgd2hlbiAo
QlMubGVuZ3RoIHJzICZndDsgMCkgKHlpZWxkIHJzKTwvZGl2PjxkaXY+Jm5ic3A7IHdoZXJlPC9k
aXY+PGRpdj4mbmJzcDsgJm5ic3A7IHVuZXNjYXBlQnl0ZVN0cmluZyA6OiAoQm9vbCwgQnl0ZVN0
cmluZykgLSZndDsgTWF5YmUgKFdvcmQ4LCAoQm9vbCwgQnl0ZVN0cmluZykpPC9kaXY+PGRpdj4m
bmJzcDsgJm5ic3A7IHVuZXNjYXBlQnl0ZVN0cmluZyAod2FzRXNjYXBlZCwgYnMpID0gY2FzZSBC
Uy51bmNvbnMgYnMgb2Y8L2Rpdj48ZGl2PiZuYnNwOyAmbmJzcDsgJm5ic3A7IEp1c3QgKF8sIGNz
KSB8IHdhc0VzY2FwZWQgJm5ic3A7ICZuYnNwOyAmbmJzcDsgLSZndDsgSnVzdCAod1VuZGVyc2Nv
cmUsIChGYWxzZSwgY3MpKTwvZGl2PjxkaXY+Jm5ic3A7ICZuYnNwOyAmbmJzcDsgSnVzdCAoYywg
Y3MpIHwgYyAvPSB3QmFja3NsYXNoICZuYnNwOy0mZ3Q7IEp1c3QgKGMsIChGYWxzZSwgY3MpKTwv
ZGl2PjxkaXY+Jm5ic3A7ICZuYnNwOyAmbmJzcDsgSnVzdCAoYywgY3MpICZuYnNwOyAmbmJzcDsg
Jm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOy0m
Z3Q7IEp1c3QgKGMsIChUcnVlLCBjcykpPC9kaXY+PGRpdj4mbmJzcDsgJm5ic3A7ICZuYnNwOyBO
b3RoaW5nICZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAm
bmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7IC0mZ3Q7IE5vdGhpbmc8L2Rpdj48L2Rp
dj48ZGl2PmBgYDwvZGl2PjxkaXY+PGJyPjwvZGl2PjxkaXY+VGhlIGFib3ZlIGZ1bmN0aW9uIGBi
bGFua0VzY2FwZWRDaGFyc2Agd2lsbCBnbyBmaW5kIGFsbCBgXGAgY2hhcmFjdGVycyBhbmQgY29u
dmVydCB0aGUgZm9sbG93aW5nIGNoYXJhY3RlciB0byBhIGBfYC4gJm5ic3A7Rm9yIGEgYDEgTUJg
IGluIG1lbW9yeSBKU09OIGBCeXRlU3RyaW5nYCwgaXQgYmVuY2hlcyBhdCBhYm91dCBgNi42IG1z
YDwvZGl2PjxkaXY+PGJyPjwvZGl2PjxkaXY+PC9kaXY+PGRpdj5JbiBhbGwgbXkgY29kZSB0aGUg
YmFzaWMgc3RyYXRlZ3kgaXMgdGhlIHNhbWUuICZuYnNwO2Bhd2FpdGAgZm9yIHRoZSBuZXh0IGJ5
dGUgc3RyaW5nLCB0aGVuIHVzZSBhbmQgYHVuZm9sZHJOYCB0byBwcm9kdWNlIGEgbmV3IGBCeXRl
U3RyaW5nYCBmb3IgeWllbGRpbmcuPC9kaXY+PGRpdj48YnI+PC9kaXY+PGRpdj5BbnlvbmUga25v
dyBvZiBhIHdheSB0byBnbyBmYXN0ZXI/PC9kaXY+PGRpdj48YnI+PC9kaXY+PGRpdj5DaGVlcnMs
PC9kaXY+PGRpdj48YnI+PC9kaXY+PGRpdj4tSm9objwvZGl2PjxkaXY+PGJyPjwvZGl2Pg==" style="min-height:0;width:0;max-height:0;max-width:0;overflow:hidden;font-size:0em;padding:0;margin:0">​</div></div></div></blockquote></div></div>