<div dir="ltr">(I mistakenly posted this thread in Haskell-cafe instead of the Haskell Pipes list. Oh well.)<br><br>On Monday, June 27, 2016 at 2:57:15 AM UTC+2, Richard A. O'Keefe wrote:<blockquote class="gmail_quote" style="margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><p><br>>      replace :: Text-> Text -> Text-> Text<br>><br>><br>> Which argument is the text to replace, which is the replacement and<br>> which is the text that should be scanned?</p><p>Considering partial application, the order that makes the most sense is<br>    - what to look for<br>    - what to replace it with<br>    - the big string to search and replace in<br></p></blockquote><div><br></div><div>Interesting, I forgot that the order of parameters can tell you things about how they are used. Did you arrive at your conclusion by assuming the "most variable" arguments come last?</div><div><br></div><blockquote class="gmail_quote" style="margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><p>> Imagine a generalized version of replace that 1) works on streams, and<br></p><p>> 2) allows replacing a sequence of texts (like, say, chapter headers)<br>> instead of replacing the same text repeatedly. It could have the<br>> following signature:<br>><br>>      replace' :: Stream (Stream (Of Text) m) m ()<br>>                  -> Stream (Stream (Of Text) m) m Void<br>>                  -> Stream (Of Text) m r<br>>                  -> Stream (Of Text) m r<br>><br>><br>> Do you find easy to intuit, just by looking at that signature, which<br>> is the function of each argument?</p><p>Absolutely not.  In fact, this crossed my personal complexity horizon<br>and is still accelerating towards some kind of singularity.</p></blockquote><div><br></div><div>Yeah, I was mostly experimenting about how to encode the the purpose of each argument in the types, without giving much thought to how complicated the signature ended up being.</div><div><br></div><div>About the first two function arguments, my reasoning was: the first stream (that returns ()) can be finite or infinite while the second (that returns Void) is necessarily infinite. Therefore it makes sense that the first is the stream of things to search for, and the second the stream of substitutions, that will be consumed as long as matches are found.</div><div> </div><blockquote class="gmail_quote" style="margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><p>The more I try to imagine a problem that this might be a solution to,<br>the less I can understand why it would be approached this way.</p><p><br></p></blockquote><div><br></div><div>A possible use case: you want to "splice" the contents of a sequence of files into another file at certain words, without having to keep whole files in memory, and without using lazy I/O.</div></div>