Thank you Richard, for taking time to explain this. I've put comments below (inline):
On Mon, Aug 5, 2019 at 10:26 AM Richard Hainsworth <rnhainswo...@gmail.com> wrote: > > William, > > I saw others were replying and between what Brad had said and what I had > said, I thought the explanations were pretty clear. > > So I'll try again. > > Comments in text below. > > On 03/08/2019 07:11, William Michels wrote: > > Hi Richard, I'm not able to come to the same conclusions. > > Specifically, the previous code examples starting with 'for lines()' > > always have to have parentheses following 'lines' (as in 'lines() > > {...}'), otherwise Perl_6 balks (examples 6 and 7 previously posted). > > This is whether 'information is being passed' or not (i.e. empty > > parentheses are required): > > > > #example 6: > > mbook:~ homedir$ perl6 -e ' for lines() { say .split(":")[0, 2, 1, > > 5].join("\t") };' six_fruits1.txt > > apple carrot banana favabean > > apricot cabbage basil fennel > > acai celery beets figs > > > > #example 6 no-parens: > > mbook:~ homedir$ perl6 -e ' for lines { say .split(":")[0, 2, 1, > > 5].join("\t") };' six_fruits1.txt > > ===SORRY!=== > > Function 'lines' needs parens to avoid gobbling block > > at -e:1 > > ------> say .split(":")[0, 2, 1, 5].join("\t") }; > > Missing block (apparently claimed by 'lines') > > at -e:1 > > ------> say .split(":")[0, 2, 1, 5].join("\t") }; > > It seems to me that the error message is quite clear. Perl 6 knows > 'lines' can take something following it, and it is expecting to get a > list which can be interpreted as lines to act upon. But then 'for' has > nothing to work on. Perl6 has figured out that you actually want the > block to go with the 'for' and not 'lines', but since there is an > ambiguity, Perl 6 errors out, and tells you what the probable mistake is. > > It has nothing to do with whether 'lines' needs () or not, but to do > with writing unambiguous code. Rather than writing 'lines()', which > personally I find distasteful, I would write: > > perl6 -e '.split(":")[0,2,1,5].join("\t").say for lines' six_fruits1.txt > > 'lines' has no () , in your words 'is bare'. But this code is > unambiguous because it is clear that `.split` etc will take the topic > (aka $_) from the 'for' and 'lines' takes its data from @_, which is > provided from the file. > > > > > #example 7: > > mbook:~ homedir$ perl6 -e 'for lines() {.split(":")[0, 2, 1, > > 5].join("\t").say};' six_fruits1.txt > > apple carrot banana favabean > > apricot cabbage basil fennel > > acai celery beets figs > > > > #example 7 no-parens: > > mbook:~ homedir$ perl6 -e 'for lines {.split(":")[0, 2, 1, > > 5].join("\t").say};' six_fruits1.txt > > ===SORRY!=== > > Function 'lines' needs parens to avoid gobbling block > > at -e:1 > > ------> {.split(":")[0, 2, 1, 5].join("\t").say}; > > Missing block (apparently claimed by 'lines') > > at -e:1 > > ------> {.split(":")[0, 2, 1, 5].join("\t").say}; > Same explanation as before. There is no difference between `say .split` > etc in your example 6, and `.split ... .say` in example 7. So the > problem you are running into has nothing to do with chaining .say or > using say as a sub. > > > > mbook:~ homedir$ perl6 --version > > This is Rakudo version 2019.07.1 built on MoarVM version 2019.07.1 > > implementing Perl 6.d. > > mbook:~ homedir$ > > > > Other Perl_6 users have replied with a general discussion of > > differences between using lines() as a method, or in a subroutine. I > > still have to review some of those comments. However, as I'm using the > > latest Perl_6 version (2019.07.1), I'm fairly confident in the results > > above (and below). > > > > Also, the examples below show that 'for lines[0..2] {...}' works, > > despite the previous error message insisting on parentheses ("Function > > 'lines' needs parens to avoid gobbling block at -e:1"). Taken > > together, the results above and below seem to indicate to me that the > > use of a bare 'lines' sub is disallowed, at least in a 'for' loop. > > Nope. What is disallowed is a bare 'lines' sub in an ambiguous context. > The idiom 'for lines { .say }' is ambiguous because > > the '{ .say }' has to be given to 'lines', but you want it to be given > to 'for'. And the reason for that choice of syntax was explained by Brad. > > This works: > > perl6 -e 'for ( lines ) { .split(":")[0, 2, 1, 5].join("\t") }' > six_fruits1.txt > > 'lines' is bare, but the brackets disambiguate the block from 'lines' . > Personally, I think this is also somewhat ugly. > > The following 'bare lines with a for' also 'works' in that no errors are > generated (Perl 6 does not disallow bare 'lines' with a for), but there > is no output so it doesn't give the desired output. Not working for me: the code doesn't return an error but it doesn't return an answer, either: mbook:~ homedir$ perl6 -e 'for (lines) { .split(":")[0, 2, 1, 5].join("\t") }' six_fruits1.txt mbook:~ homedir$ Okay...I see what happened. The ".say" call needs to be added at the end: mbook:~ homedir$ perl6 -e 'for (lines) { .split(":")[0, 2, 1, 5].join("\t").say }' six_fruits1.txt apple carrot banana favabean apricot cabbage basil fennel acai celery beets figs mbook:~ homedir$ > > perl6 -e 'for lines {} { .split(":")[0, 2, 1, 5].join("\t") }' > six_fruits1.txt > > Obviously, 'lines' has been given something to operate on, and in this > case it is interpreted not as a block, but an empty hash. And since > 'lines' had been given an explicit argument, Perl 6 did not know to > provide the data from six_fruits1.txt to anything, so the data was ignored. Okay, same result as earlier: I need to add ".say" at the end to get any output. I see that a separate "{}" returns nothing, but if I put the "{}" adjacent to "lines" as in "lines{}" all of a sudden it works and gives the correct answer. Not only does "lines{}" work, but "lines()" and "lines[]" works. What doesn't seem to work is a bare "lines" as noted previously: mbook:~ homedir$ perl6 -e 'for lines {} { .split(":")[0, 2, 1, 5].join("\t") }' six_fruits1.txt mbook:~ homedir$ perl6 -e 'for lines {} { .split(":")[0, 2, 1, 5].join("\t").say }' six_fruits1.txt mbook:~ homedir$ perl6 -e 'for lines{} { .split(":")[0, 2, 1, 5].join("\t").say }' six_fruits1.txt apple carrot banana favabean apricot cabbage basil fennel acai celery beets figs mbook:~ homedir$ perl6 -e 'for lines() { .split(":")[0, 2, 1, 5].join("\t").say }' six_fruits1.txt apple carrot banana favabean apricot cabbage basil fennel acai celery beets figs mbook:~ homedir$ perl6 -e 'for lines[] { .split(":")[0, 2, 1, 5].join("\t").say }' six_fruits1.txt apple carrot banana favabean apricot cabbage basil fennel acai celery beets figs mbook:~ homedir$ perl6 -e 'for lines { .split(":")[0, 2, 1, 5].join("\t").say }' six_fruits1.txt ===SORRY!=== Function 'lines' needs parens to avoid gobbling block at -e:1 ------> .split(":")[0, 2, 1, 5].join("\t").say }<EOL> Missing block (apparently claimed by 'lines') at -e:1 ------> .split(":")[0, 2, 1, 5].join("\t").say }<EOL> > > Almost the same thing, note the space between 'lines' and '()': > > perl6 -e 'for lines () { .split(":")[0, 2, 1, 5].join("\t") }' > six_fruits1.txt > > Here, 'lines' is given an empty list, viz. ' ()', the preceding space > telling Perl 6 that '()' is a list, not a signature > > However, "bare lines" is not "disallowed" for a 'for'. > > Hope this helps. (I said bare 'lines', not 'bare lines'). But I think I see what you're saying. First I add the ".say" method below (otherwise i get no result), then i eliminate everything but { .say} inside the curly braces. This actually lets me feed an object (for lack of a better word) into the block: mbook:~ homedir$ perl6 -e 'for lines () { .split(":")[0, 2, 1, 5].join("\t") }' six_fruits1.txt mbook:~ homedir$ perl6 -e 'for lines() { .split(":")[0, 2, 1, 5].join("\t") }' six_fruits1.txt mbook:~ homedir$ perl6 -e 'for lines () { .split(":")[0, 2, 1, 5].join("\t").say }' six_fruits1.txt mbook:~ homedir$ perl6 -e 'for lines() { .split(":")[0, 2, 1, 5].join("\t").say }' six_fruits1.txt apple carrot banana favabean apricot cabbage basil fennel acai celery beets figs mbook:~ homedir$ perl6 -e 'for (lines) { .split(":")[0, 2, 1, 5].join("\t").say }' six_fruits1.txt apple carrot banana favabean apricot cabbage basil fennel acai celery beets figs mbook:~ homedir$ perl6 -e 'for lines () { .split(":")[0, 2, 1, 5].join("\t").say }' mbook:~ homedir$ perl6 -e 'for lines ("a\nb\n") { .split(":")[0, 2, 1, 5].join("\t").say }' Use of Nil in string context in block at -e line 1 Use of Nil in string context in block at -e line 1 Use of Nil in string context in block at -e line 1 a Use of Nil in string context in block at -e line 1 Use of Nil in string context in block at -e line 1 Use of Nil in string context in block at -e line 1 b mbook:~ homedir$ perl6 -e 'for lines ("a\nb\n") { .say }' a b mbook:~ homedir$ Okay. How to express this in simple English? Writing a one-liner "for" loop for use on a shell command line, you can feed lines into a block using 'lines()' and adding the target file at the end. Or you can write "for lines ("line_1\nline_2\n") and then the functions you want to perform inside the block. Correct? Best Regards, Bill. > > > > --Best Regards, Bill. > > > > #example 10: > > mbook:~ homedir$ perl6 -e 'for lines { say .split(":")[0, 2, 1, > > 5].join("\t") };' six_fruits1.txt > > ===SORRY!=== > > Function 'lines' needs parens to avoid gobbling block > > at -e:1 > > ------> say .split(":")[0, 2, 1, 5].join("\t") }; > > Missing block (apparently claimed by 'lines') > > at -e:1 > > ------> say .split(":")[0, 2, 1, 5].join("\t") }; > > > > #example 11: > > mbook:~ homedir$ perl6 -e 'for lines() { say .split(":")[0, 2, 1, > > 5].join("\t") };' six_fruits1.txt > > apple carrot banana favabean > > apricot cabbage basil fennel > > acai celery beets figs > > > > #example 12: > > mbook:~ homedir$ perl6 -e 'for lines[0..2] { say .split(":")[0, 2, 1, > > 5].join("\t") };' six_fruits1.txt > > apple carrot banana favabean > > apricot cabbage basil fennel > > acai celery beets figs > > > > > > On Fri, Aug 2, 2019 at 1:20 AM Richard Hainsworth > > > > <rnhainswo...@gmail.com> wrote: > >> Not quite sure what sort of "rule" you want. > >> > >> You used () and [] which do different things and the results were exactly > >> what I would expect. They are covered in the documentation. Basically, () > >> without a space, eg xxxx() not xxxx (), is used to pass information to the > >> sub or method xxxx. > >> If no information is being passed, then no need to use (). The way xxxx > >> responds to no data provided depends on the way xxxx is written. The > >> programmer could provide default values for the arguments it expects. > >> Perl6 also makes the value of the default variable, eg $_, to xxxx. > >> If you put a space between xxxx (), then () is interpreted as an empty > >> list and provide to xxxx as a single piece of information. > >> [] Are used to dereference a list (sequence or array, they are all > >> slightly different). > >> > >> I'll comment more below. Sometimes I think through the process using > >> slightly different and less exact words. My comments are illustrative. > >> > >> On Fri, 2 Aug 2019, 04:50 William Michels, <w...@caa.columbia.edu> wrote: > >>> Hi Richard, I'm trying to figure out when the parentheses in 'lines()' > >>> can be dropped, and 'lines' used instead. Any pointers? I have about > >>> nine or so working examples below, but formulating a clear > >>> rule-of-thumb is proving elusive. Any help appreciated, --Best, Bill. > >>> > >>> # test file: six_fruits1.txt > >>> mbook:~ homedir$ cat six_fruits1.txt > >>> apple:banana:carrot:dragonfruit:eggplant:favabean > >>> apricot:basil:cabbage:dill:escarole:fennel > >>> acai:beets:celery:daikon:endive:figs > >>> > >>> mbook:~ homedir$ perl6 -e '.say for lines()' six_fruits1.txt > >>> apple:banana:carrot:dragonfruit:eggplant:favabean > >>> apricot:basil:cabbage:dill:escarole:fennel > >>> acai:beets:celery:daikon:endive:figs > >> Here 'lines ()' is the same as 'lines'. > >> The program in the string after -e is provided with the data inside the > >> file. > >>> > >>> mbook:~ homedir$ perl6 -e '.say for lines' six_fruits1.txt > >>> apple:banana:carrot:dragonfruit:eggplant:favabean > >>> apricot:basil:cabbage:dill:escarole:fennel > >>> acai:beets:celery:daikon:endive:figs > >> The top two are equivalent > >>> > >>> mbook:~ homedir$ perl6 -e '.say for lines("a\nb\n")' six_fruits1.txt > >>> a > >>> b > >> Here you provided data to 'lines' which it was able to interpret as a set > >> of lines. So it printed them. The data in six_fruits is ignored because > >> you provided the data explicitly. > >>> > >>> mbook:~ homedir$ perl6 -e '.say for lines[0]' six_fruits1.txt > >>> apple:banana:carrot:dragonfruit:eggplant:favabean > >> Six_fruits has 3 lines. Lines has processed the data. But you wrote '[0]' > >> which extracted the first line, and that was processed by the 'for' loop. > >> In other words the 'for' was only given one piece of information to > >> process. > >>> > >>> mbook:~ homedir$ perl6 -e '.say for lines[0..1]' six_fruits1.txt > >>> apple:banana:carrot:dragonfruit:eggplant:favabean > >>> apricot:basil:cabbage:dill:escarole:fennel > >> The '[0..1]' extracts the first three pieces of data from 'lines' and they > >> are processed by the 'for' > >>> > >>> mbook:~ homedir$ perl6 -e ' for lines() { say .split(":")[0, 2, 1, > >>> 5].join("\t") };' six_fruits1.txt > >>> apple carrot banana favabean > >>> apricot cabbage basil fennel > >>> acai celery beets figs > >> Could be just 'lines', which provides a list of the lines in the file to > >> the 'for' > >> Inside the 'for' the data is in the topic or default variable. You could > >> access it as $_ but '.split' accesses it automatically. Split generates > >> another list. '[0,2,1,5]' extracts the relevant elements of the list and > >> generates another list which is passed to the'join'. The output from join > >> is passed to 'say' which is written in sub form. Sub form means you write > >> the name of the sub first, then you write where the data is coming from. > >> > >>> mbook:~ homedir$ perl6 -e ' for lines() {.split(":")[0, 2, 1, > >>> 5].join("\t").say};' six_fruits1.txt > >>> apple carrot banana favabean > >>> apricot cabbage basil fennel > >>> acai celery beets figs > >> Exactly the same for perl6 as before except that 'say' is written in sub > >> form above and in method form here. Method form means you can append the > >> 'say' to a chain of processing units. > >>> > >>> mbook:~ homedir$ perl6 -e 'for "six_fruits1.txt".IO.lines() > >>> {.split(/\:/)[0, 2, 1, 5].join("\t").say};' > >>> apple carrot banana favabean > >>> apricot cabbage basil fennel > >>> acai celery beets figs > >> Here just accessing the data in the file explicitly in perl6. > >>> > >>> mbook:~ homedir$ perl6 -e 'for "six_fruits1.txt".IO.lines > >>> {.split(/\:/)[0, 2, 1, 5].join("\t").say};' > >>> apple carrot banana favabean > >>> apricot cabbage basil fennel > >>> acai celery beets figs > >> Same as above. No () on lines > >>> > >>> > >>> > >>> > >>> On Mon, Jul 29, 2019 at 1:07 AM Richard Hainsworth > >>> <rnhainswo...@gmail.com> wrote: > >>>> Also no need for all the brackets > >>>> > >>>> .say for lines; > >>>> > >>>> This is quite idiomatic Perl 6 and not golfing > >>>> > >>>> On Mon, 29 Jul 2019, 07:13 Joseph Brenner, <doom...@gmail.com> wrote: > >>>>>> Hmmm. I would expect that to be in the Perl 5 to Perl 6 Migration > >>>>>> Guides, but I do not see it there. > >>>>> Exactly, I was just looking there, and I ended up playing around with > >>>>> the method form of lines, and didn't think to try the function > >>>>> form of it. > >>>>> > >>>>> To summarize, if the goal is to write a "simple_echo" script that > >>>>> can work with a file name or with lines on standard input: > >>>>> > >>>>> simple_echo lines.txt > >>>>> cat lines.txt | simple_echo > >>>>> > >>>>> The perl5 version would probably be: > >>>>> > >>>>> #!/usr/bin/env perl > >>>>> while(<>){ > >>>>> print; > >>>>> } > >>>>> > >>>>> The perl6 version would be something like: > >>>>> > >>>>> #!/usr/bin/env perl6 > >>>>> use v6; > >>>>> for lines() { > >>>>> say $_; > >>>>> } > >>>>> > >>>>> > >>>>> The kind of thing I was playing with was: > >>>>> > >>>>> #!/usr/bin/env perl6 > >>>>> use v6; > >>>>> my @lines = $*ARGFILES.IO.lines; > >>>>> say @lines; > >>>>> > >>>>> That works for lines from a file, but not from standard input, and the > >>>>> error message isn't tremendously helpful: > >>>>> > >>>>> No such method 'lines' for invocant of type 'IO::Special' > >>>>> > >>>>> > >>>>> > >>>>> > >>>>> On 7/28/19, Bruce Gray <robertbrucegr...@gmail.com> wrote: > >>>>>> > >>>>>>> On Jul 28, 2019, at 6:20 PM, Joseph Brenner <doom...@gmail.com> wrote: > >>>>>>> > >>>>>>> I was just wondering if there's some direct analog in perl6 to the > >>>>>>> perl5 construct: > >>>>>>> > >>>>>>> while(<>){ ... } > >>>>>>> > >>>>>>> If I'm planning on passing a filename on the command-line, I can just > >>>>>>> get it out of $*ARGFILES easily enough, but what if I also wanted it > >>>>>>> to work on lines passed in via standard input? > >>>>>> > >>>>>> `lines` , as a sub instead of a method, and no arguments. > >>>>>> > >>>>>> See: https://docs.perl6.org/routine/lines#(Cool)_routine_lines > >>>>>> Without any arguments, sub lines operates on $*ARGFILES, which > >>>>>> defaults to > >>>>>> $*IN in the absence of any filenames. > >>>>>> > >>>>>> For example: > >>>>>> perl6 -e 'say .join("\t") for lines().rotor(4);' > >>>>>> path/to/file.txt > >>>>>> > >>>>>> Hmmm. I would expect that to be in the Perl 5 to Perl 6 Migration > >>>>>> Guides, > >>>>>> but I do not see it there. > >>>>>> > >>>>>> — > >>>>>> Hope this helps, > >>>>>> Bruce Gray (Util of PerlMonks) > >>>>>> > >>>>>>