14

Sometimes I'll start writing a chain of method calls at the Perl 6 REPL, like:

".".IO.dir.grep(...).map(...).

...and then I realize that what I want to do with the final list is print every element on its own line. I would expect sequences to have something like an each method so I could end the chain with .each(*.say), but there's no method like that that I can find. Instead I have to return to the beginning of the line and prepend .say for. It feels like it breaks up the flow of my thoughts.

It's a minor annoyance, but it strikes me as such a glaring omission that I wonder if I'm missing some easy alternative. The only ones I can think of are ».say and .join("\n").say, but the former can operate on the elements out of order (if I understand correctly) and the latter constructs a single string which could be problematically large, depending on the input list.

jjmerelo
  • 22,578
  • 8
  • 40
  • 86
Sean
  • 29,130
  • 4
  • 80
  • 105

2 Answers2

11

You can roll your own.

use MONKEY;

augment class Any 
{ 
    method each( &block )
    {
        for self -> $value { 
            &block( $value );
        }
    }
};

List.^compose;
Seq.^compose;

(1, 2).each({ .say });
(2, 3).map(* + 1).each({ .say });

# 1
# 2
# 3
# 4

If you like this, there's your First CPAN module opportunity right there.

Holli
  • 5,072
  • 10
  • 27
  • 1
    Great answer and idea for a CPAN module. You might consider mentiong it can be made into a regular sub and called with `.&each()`, in case they don't want to fuddle with augmenting. – user0721090601 Oct 03 '19 at 01:32
  • Using the `.&each()` format comes with downsides, such as being required to stick to a single line (or use rather unwieldy `\ ` all over the place). – Tyil Oct 07 '19 at 14:35
8

As you wrote in the comment, just an other .map(*.say) does also create a line with True values when using REPL. You can try to call .sink method after the last map statement.

".".IO.dir.grep({$_.contains('e')}).map(*.uc).map(*.say).sink
LuVa
  • 2,288
  • 2
  • 10
  • 20
  • I suppose...but then the REPL will spit out a list of `True` values of the same length as the input list. Not ideal. – Sean Oct 02 '19 at 19:05
  • `".".IO.dir.grep(*.contains("e")).map(*.uc).map: {.say; Empty}` will do the same, but only mention an empty list in the REPL – Elizabeth Mattijsen Oct 02 '19 at 22:32
  • I believe the REPL is meant to not output the result of a line if there has been output; it does that by calling `tell` on the out filehandle before and after the command and compares them, I think? so something might be going wrong with that logic. – timotimo Oct 03 '19 at 19:09