kaatunut has asked for the wisdom of the Perl Monks concerning the following question:

I am writing a little application in C, and after getting totally sick of basically reinventing a scripting language for that program, I decided to embed a little perl. For this, I need to tinker with the syntax:

Case: I want a function called 'on' that will take two code blocks, 'when' ($_ = line to be matched, returns true if matches) and 'then' (if 'when' was true, run 'then' with $_ = modifiable typeglob to the line to be matched).

Clarification:
then={ /foo/ }
when={ tr/ab/ba/; }
$line="abba is kind of foo";

After calling on with proper parameters,
$line eq "baab is kind of foo"

After tinkering for a while (and reading the try/catch example), I came up with this:

sub on (&$$) { my($f1,$f2,$l)=@_; local $_=$$l; if (&$f1) { local *_=$l; &$f2($l); } } sub action (&) { shift } $a="abba is foo"; on { /foo/ } action { tr/ab/ba/; },\$a; print "$a\n";

And lo! It works. Now, what's the point, and why is this in Seekers, you ask. Well...

At this point it becomes evident how similar this is to perl grep. However, grep has one magical power I don't: It can take EXPR or BLOCK as its 1st parameter. How do I?

Intuitive solution one, write two functions called 'on' with different prototypes. Meep! Prototype mismatch.

Intuitive solution two, ditch prototypes and figure out what we are doing by looking at the parameter list. Meep! Syntax error follows.

How do I manage?

Issue two, rather minor though, is that I'd like to rid myself of the 'action' keyword and just write the two code blocks like this: on { /foo/ } { tr/ab/ba/; },\$a;

But I couldn't figure out any way to do without that dummy sub action, everything resulted in obscure syntax errors.

-Kaatunut

Replies are listed 'Best First'.
Re: Polymorphic prototypes? (creating new syntax)
by Corion (Patriarch) on Apr 08, 2001 at 16:32 UTC

    I don't know how to exactly recreate the magic that surrounds grep, but at least it's somewhat possible by taking some magic from MeowChows treemap node :

    #!/usr/bin/perl -w use strict; sub on { my($f1,$f2,$l)=@_; my $parmtype = ref $f1; print "f1: $parmtype\n"; if ($parmtype eq 'CODE') { local $_=$$l; if (&$f1) { local *_=$l; &$f2($l); } }; } my $foo="abba is foo"; on sub{ /foo/ }, sub { tr/ab/ba/; }, \$foo; print "$foo\n"; on "bla", sub { tr/ab/ba/; }, \$foo;

    As you see, it's still far from perfect, as you'll have to use the sub keyword for your code parameters, but at least your subroutine on can now determine through the $type parameter, whether CODE or something else was passed in.

Re (tilly) 1: Polymorphic prototypes? (creating new syntax)
by tilly (Archbishop) on Apr 08, 2001 at 19:46 UTC
    The problem with having multiple prototypes for the same function is that Perl doesn't know how to dispatch on the prototype. (An idea from C++ which people have mixed opinions on.)

    I would use intuitive solution 2 and use the sub keyword to generate closures on the fly. That is instead of typing

    my_func {block1} {block2} $arg;
    you would type:
    my_func(sub {block1}, sub {block2}, $arg);
    Now if that is not the syntax you want, you can try (I have not so no idea how hard this will be) to play games with Filter::Util::Call to define a custom language. Similarly you could do something like use Parse::RecDescent to parse the configuration, generate equivalent Perl code from slight markups, and then eval that.

    Too get a sense of how far you can go with those ideas, take a look at Lingua::Romana::Perligata (but don't blame me if you lose your sanity)...

      Too get a sense of how far you can go with those ideas, take a look at Lingua::Romana::Perligata (but don't blame me if you lose your sanity)...

      :) I almost started studying latin just to be able to code in Perligata... I just find the idea of coding perl in latin incredibly cool.

      Dispatch on prototype? What do you mean? That expression is alien to me, but I don't see a problem with prototype polymorphism. Hook up a list of possible matches for invocation compile-time and only if the sub is prototyped to be polymorphic, if the number of matches != 1, complain. Mmm? Of course this would only work with prototypes, who already generate syntax errors on incorrect invocation. How this relates to anonymous functions and whatnot, I dunno, but you can't defined prototypes for those anyways, can you?

      -Kaatunut

        By dispatch on prototype I mean that when Perl looks up a function it can figure out what function to call based on the name and the look of the arguments.

        As for whether it is doable, probably. It would be hairy. It would not fit well in the list-oriented nature of Perl. People often find the APIs they create with such facilities to be very confusing. And Perl does not support it because it does not support having 2 functions in the same package of the same name at the same time.

        Anyways about prototypes, I completely side with Tom Christiansen on this. Unless you have a darned good reason you need them, they are a bad idea in Perl...

        While you're at it, take a look at Michael Schwern's DNA and Leon Brocard's Buffy, then you can code Perl in DNA sequences and various capitalizations of Buffy and have it work!

        All these magics are due to Paul Marquess' Filter::Cpp (I believe it's called).

        Yes, I have seen it.

        But note that it does not and cannot be readily extended to allow dispatching based on what prototype coercion finally made the code not a syntax error. Which is what was being asked for.

        So it doesn't solve the problem at hand.

        Besides that it is a performance hit, and there is considerable conceptual complexity in the APIs that it makes possible. That complexity makes me personally inclined to avoid it and seek to rethink problems in a simpler way rather than add that complexity to the problem at hand.

        All of which were reasons why I didn't mention it before...