develooper Front page | perl.perl6.language | Postings from March 2005

Re: Logic Programming with Rules (and Argument Patterns)

Thread Previous | Thread Next
Rod Adams
March 9, 2005 04:02
Re: Logic Programming with Rules (and Argument Patterns)
Message ID:
Luke Palmer wrote:

>Rod Adams writes:
>Or you could avoid the global modifier and write your tests in <( )>
>blocks instead... after all, that's what it's there for.
I *knew* I had seen a syntax for that before... I just didn't see it 
when I scanned S05 for it.

I still want the :z modifier for matching zero length strings. That 
makes sense to be global.

>>The really big problem, however, is the lack of generators.
>>I'll establish a working definition of "generator" as "something which
>>offers a possible value, giving the new value each time the expression
>>is backtracked over, and fails when there are no more values to give".
>One generator is the * combinator.  It gives the longest string, then
>the next shorter, then the next shorter...
I agree that * works that way... when you're matching against a 
string... which I'm not. I intend for the basic call to be something 
like C< "" ~~ /<test(1)>/ >, or more likely just C< /<test(1)>/ >. I 
won't care what the current topic is. I'll match the empty string, and 
everything that includes it, or nothing at all. My entire rule set will 
be a series of really complex zero-length assertions.

>>Clearly, desirable generators include lazy lists, arrays, and
>>closures. All of which P6RE supports as ways of attempting different
>>rules/strings to match against, but not as different values to assign
>>a given $<var> to feed into later rules. Capturing assumes a string to
>>match and capture against. Capturing the null string that I "match" is
>>not terribly useful.
>>The only suggestion I can give for how to do this is by introducing the
>>hyper operator. I'm very open to other ideas, because this one does not
>>sit well with me, but it's all I've got at the moment. So, to give an
>>array as a generator, one could write:
>>   /:a {$<x> »=« @values} <test($<x>)>/
>You could do all of this with a library of rules.
>    / $<x>:=<generate(@values)>  <test($<x>)> /
I don't think this does what I want. In this, &generate returns a rule 
or string of some kind, matches the string being tested, captures what 
matches, and then binds the capture to $<x>.

I have no underlying string, so the match fails right there. I want to 
bind/assign to the variable _without_ matching, but _with_ backtracking 
and iteration over several values.

I also now notice that I would need a C< let > in my example above.

>How the <generate> rule is actually written is getting into some rule
>engine internal stuff, but we're making sure that the rule engine has
>enough hooks to do that.
There were some thoughts in the back of my head about how I actually 
wanted a closure to be handled as a generator. I see the need to 
initialize it many separate times, once on each forward attempt, can be 
repeated if something after it fails, and something before it has an 
alternative. But I wanted the basic concept out there before I tried 
diving into that kind of detail.

>Maybe we could unify the pattern proposal and your generation ideas for logic programming.
There might be unification with logical programming to be had, but I'm 
not sure it's with the generation part of things.

>    @array[$^i]  # returns a lazy pattern of everything in @array, bound
>                 # together with the corresponding $i
How is this any different from just @array ?

>    (@array[$^i]).GENERATE   # generates every element of @array
>Now, let's just combine that with another array pattern:
>    @a[$^i] + @b[$^i]  # returns lazy pattern of everything in @a
>                       # added to its corresponding element in @b
>    (@a[$^i] + @b[$^i]).GENERATE  # vector sum
>Now if we just spell .GENERATE with «»:
>    « @a[$^i] + @b[$^i] »
>We have my tensor-hyper proposal back.
This example is easily done as:

    @a »+« @b

But it's also not terribly far removed from my hyperthreader operator in 
the Junctions thread (oh, when, oh when is Damian coming back?). There 
are differences, but see if that does what you need.

Not to mention that « » are already taken in that context as q:w// 

>Now «» could have a similar meaning within rules, which would give you
>your generator.
>    # print everything in @array that matches test()
>    / $<x> := «@array[$^i]»  <( test($<x>) )>  { say $<x>; fail } /
Problems with this:
1) « » in RE's are already taken for non-capturing meta's. And binding 
doesn't work if you don't capture.
2) you're still trying to match the value against the string.

Not really a problem, but I had C<  <test($<x>)> >, not C< 
<(test($<x>))> > on purpose. I was feeding into a rule, not a function.

>The biggest question is how this interacts with sub calls.  We can't
>really expect sub calls to be pattern-aware: that puts constraints on
>what we're allowed to do in a sub (no side-effect constraints; gee,
>those kinds of constraints really go a long way).  But &test could
>certainly implement a GENERATE method:
>    sub is_prime(
>        $x will GENERATE { primes() }
>    )
>    {
>        ?grep { $_ == $x } primes()
>    }
>The will generate says that the sub can accept a generic pattern and
>will fill it in on the spot.
I don't see what this gives me over a regular lazy list generation with 

-- Rod Adams

Thread Previous | Thread Next Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at | Group listing | About