niner / Inline-Perl5

Use Perl 5 code in a Raku program
Artistic License 2.0
94 stars 30 forks source link

how do you run Perl functions that take blocks as arguments? #161

Open stuart-little opened 3 years ago

stuart-little commented 3 years ago

I am trying to do this:

#!/usr/bin/env perl6
use v6;

use List::AllUtils:from<Perl5> <bsearchidx>;

say bsearchidx {$_ - 1} (1,2,3);

as per that module's docs. The result in Raku:

===SORRY!=== Error while compiling <path-to-script>
Strange text after block (missing semicolon or comma?)
at <path-to-script>:6
------> say bsearchidx {$_ - 1}⏏ (1,2,3);
    expecting any of:
        infix
        infix stopper
        postfix
        statement end
        statement modifier
        statement modifier loop
vendethiel commented 3 years ago

In Raku, there's no implicit comma after a block. You need to actually write out bsearchidx {$_ - 1}, (1,2,3);. That's not related to Inline::Perl5

stuart-little commented 3 years ago

Sure, that was the first thing I tried.. However:

#!/usr/bin/env perl6
use v6;
use List::AllUtils:from<Perl5> <bsearchidx>;
say bsearchidx {$_ - 1}, (1,2,3);

Result:

Use of uninitialized value of type Any in numeric context
  in block <unit> at <script-path> line 6

-1

It should find the 1 at position 0, and hence return 0. So this doesn't play well with functions like bsearchidx, apparently.

lizmat commented 3 years ago

Perhaps Array::Sorted::Util can be of use?

stuart-little commented 3 years ago

Perhaps Array::Sorted::Util can be of use?

Oh, I don't doubt it. I can also EVAL arbitrary Perl5 code, as noted here, and I've gotten bsearchidx working that way.

But this doesn't quite resolve the matter generally: there are a great many functions all over the place in Perl5 packages that are advertised as taking arguments of the form

function { BLOCK } @LIST

(e.g. reduce, first, etc. etc.). I would still like to know what the best way is to render those in Raku by inlining. This comma/no-comma issue makes them all choke, it seems:

#!/usr/bin/env perl6
use v6;
use List::Util:from<Perl5> <first>;
say first {$_ > 0} (1,2,3);

complains without the comma because it's not there, and with the comma because of a

Use of uninitialized value of type Any
niner commented 3 years ago

Basically what's needed here is mapping Raku's $ to Perl's. That should be quite possible as $ is available to XS code as UNDERBAR. It will cost a bit of performance though as we'll have to set this up for every call, since we don't know whether it's needed or not.

However that's not yet implemented. But until it is, one can access Perl's $_ directly:

use List::Util:from<Perl5> <first>;
say first { %*PERL5<$_> %% 3 }, 1, 2, 3, 4

Unfortunately I found a bug when trying this. Notice the absence of parenthesis in my example? That's because it'd pass the whole list as a single item to first otherwise. It works as expected when calling fully qualified though:

use List::Util:from<Perl5>;
say List::Util::first { %*PERL5<$_> %% 3 }, (1, 2, 3, 4)
stuart-little commented 3 years ago

That worked, thank you! I'm glad I asked :).

tbrowder commented 3 years ago

On Mon, May 3, 2021 at 13:07 stuart-little @.***> wrote:

That worked, thank you! I'm glad I asked :).

And if you could put that in the README that would be great! I look forward to trying it out.