Thread overview
optional process
Nov 29, 2019
Paul Backus
Dec 05, 2019
Taylor Hillegeist
Dec 05, 2019
Paul Backus
Dec 05, 2019
Taylor Hillegeist
Dec 06, 2019
Paul Backus
Dec 06, 2019
Taylor Hillegeist
November 29, 2019
When using the standard library. and making command-line applications I find myself wanting optional processes in line. for me, this typically makes the following structure.

bool sortOutput;

if(sortOutput){
read(Textfile)
   .splitter("\n")
   .filter(a=>a.contains("data))
   .sort!("a < b").writeln();

}else{

read(Textfile)
   .splitter("\n")
   .filter(a=>a.contains("data))
   .writeln();
}

I know phobos has choose which is close.
But what I want is something like:

bool sortOutput;

if(sortOutput){
read(Textfile)
   .splitter("\n")
   .filter(a=>a.contains("data))
   .doif(sortOutput,sort!("a < b"))
   .writeln();
November 29, 2019
On Friday, 29 November 2019 at 15:17:35 UTC, Taylor R Hillegeist wrote:
> I know phobos has choose which is close.
> But what I want is something like:
>
> bool sortOutput;
>
> if(sortOutput){
> read(Textfile)
>    .splitter("\n")
>    .filter(a=>a.contains("data))
>    .doif(sortOutput,sort!("a < b"))
>    .writeln();

import std.functional: pipe;

bool sortOutput;

read(Textfile)
   .splitter("\n")
   .filter!(a=>a.contains("data))
   .pipe!((output) {
      if (sortOutput)
         return output.sort!("a < b");
      else
         return output;
   })
   .writeln(); // maybe you meant each!writeln ?
November 29, 2019
On Friday, 29 November 2019 at 15:24:31 UTC, Paul Backus wrote:
> On Friday, 29 November 2019 at 15:17:35 UTC, Taylor R Hillegeist wrote:
>> I know phobos has choose which is close.
>> But what I want is something like:
>>
>> bool sortOutput;
>>
>> if(sortOutput){
>> read(Textfile)
>>    .splitter("\n")
>>    .filter(a=>a.contains("data))
>>    .doif(sortOutput,sort!("a < b"))
>>    .writeln();
>
> import std.functional: pipe;
>
> bool sortOutput;
>
> read(Textfile)
>    .splitter("\n")
>    .filter!(a=>a.contains("data))
>    .pipe!((output) {
>       if (sortOutput)
>          return output.sort!("a < b");
>       else
>          return output;
>    })
>    .writeln(); // maybe you meant each!writeln ?

That is actually exactly the kind of thing I was looking for. (it gets the job done without repeats) I would still like it to be in the first form though e.g. doif. it would keep the code cleaner.
Thank you for this.  (also yes I just made up the example so .each!writeln is appropriate it would be surprising to me if that was the only error)

December 05, 2019
On Friday, 29 November 2019 at 15:24:31 UTC, Paul Backus wrote:

>    .pipe!((output) {
>       if (sortOutput)
>          return output.sort!("a < b");
>       else
>          return output;
>    })
>    .writeln(); // maybe you meant each!writeln ?

Why pipe as apposed to compose?

Pipes functions in sequence. It offers the same functionality as compose, but with functions specified in reverse order. This may lead to more readable code in some situation because the order of execution is the same as lexical order.

How does this not reverse the range?


December 05, 2019
On Thursday, 5 December 2019 at 15:30:52 UTC, Taylor Hillegeist wrote:
> On Friday, 29 November 2019 at 15:24:31 UTC, Paul Backus wrote:
>
>>    .pipe!((output) {
>>       if (sortOutput)
>>          return output.sort!("a < b");
>>       else
>>          return output;
>>    })
>>    .writeln(); // maybe you meant each!writeln ?
>
> Why pipe as apposed to compose?
>
> Pipes functions in sequence. It offers the same functionality as compose, but with functions specified in reverse order. This may lead to more readable code in some situation because the order of execution is the same as lexical order.
>
> How does this not reverse the range?

range
    .pipe!someFunction
    .each!writeln;

is the same as

range
    .someFunction
    .each!writeln;

So why use pipe? Because in this case, the function we want to apply is a lambda, and you can't call lambdas with UFCS.
December 05, 2019
On Thursday, 5 December 2019 at 15:43:30 UTC, Paul Backus wrote:
> On Thursday, 5 December 2019 at 15:30:52 UTC, Taylor Hillegeist wrote:
>> On Friday, 29 November 2019 at 15:24:31 UTC, Paul Backus wrote:
>>
>>>    .pipe!((output) {
>>>       if (sortOutput)
>>>          return output.sort!("a < b");
>>>       else
>>>          return output;
>>>    })
>>>    .writeln(); // maybe you meant each!writeln ?
> range
>     .someFunction
>     .each!writeln;
>
> So why use pipe? Because in this case, the function we want to apply is a lambda, and you can't call lambdas with UFCS.

I agree with this.

I wasn't clear enough in my question though.
I was trying to distinguish between std.functional.compose and std.functional.pipe
they look very the same. Pipe says it reverses functions order. Which makes no sense to me.
December 06, 2019
On Thursday, 5 December 2019 at 17:27:45 UTC, Taylor Hillegeist wrote:
>
> I agree with this.
>
> I wasn't clear enough in my question though.
> I was trying to distinguish between std.functional.compose and std.functional.pipe
> they look very the same. Pipe says it reverses functions order. Which makes no sense to me.

input.pipe!(f, g, h) == input.f.g.h == h(g(f(input)))

input.compose!(f, g, h) == input.h.g.f == f(g(h(input)))
December 06, 2019
On Friday, 6 December 2019 at 05:09:58 UTC, Paul Backus wrote:
> On Thursday, 5 December 2019 at 17:27:45 UTC, Taylor Hillegeist wrote:
>>
>> I agree with this.
>>
>> I wasn't clear enough in my question though.
>> I was trying to distinguish between std.functional.compose and std.functional.pipe
>> they look very the same. Pipe says it reverses functions order. Which makes no sense to me.
>
> input.pipe!(f, g, h) == input.f.g.h == h(g(f(input)))
>
> input.compose!(f, g, h) == input.h.g.f == f(g(h(input)))

This is surprisingly clear. I guess I never thought to put multiple functions into pipe that way. It also makes sense why pipe would be the default choice.

Thank you, Paul, for the great answer.