Re: Pondering parameterized operators
--- Luke Palmer [EMAIL PROTECTED] wrote: Yeah, that's true. But note that you can't do that black magic you were speaking of earlier: $a [ (cond ?? infix:+ : infix:*) but tighter(infix:*) ] $b Because we can't choose the precedence of an operator after we parse it... unless we're doing bottom up, which we're not. I do think that the infix [] construct would have to have a fixed precedence. Run time or compile time? If the [] is a compile time operation, it doesn't matter, of course, since everything is done. If the precedence of [] can vary, or if user-ops can vary their precedence, the parser will have to have some sort of late reevaluation mechanism. This fits in with the recompile if you change the world thread from last week, I guess. It also ties in kind of nicely with the feel of Damian's OOPerl book: making objects out of unlikely things. In this case, we're making operators out of them. my op1; my op2; sub foo { my $x = $^a op1 $^b op2 $^c; print Foo: . $x . \n; } # (Luke: Because these are literal lists, I don't need :=, right?) (op1, op2) := (infix:+, infix:*); foo(3,4,5); # Prints 23 (op1, op2) := (op2, op1); foo(3,4,5); # Prints 17 (27 if the parser doesn't rescan :-) =Austin
Re: Pondering parameterized operators
Austin Hastings [EMAIL PROTECTED] writes: [Eirik wrote:] Let us see ... somewhat speculative and probably short-of-the-mark generalization coming up: macro infix:[ ($lhs, $op, $rhs) is parsed(/(Perl6.expr) \] (Perl6.expr)/) { return { $op($lhs, $rhs) }; } (Precedence? Err ... the left hand side has already been parsed, so infix:[ must be of fixed precedence to the left hand side, right? Damn, I thought I had it ...) This is text replacement, not expression evaluation. You do have it from where I sit. Text replacement? This is returning a closure, not text. But even if this is a case of text replacement, I get the first parameter, $lhs, from text that has already been parsed. # Note: Need a way to parse nested []'s macro [ ($whosit) is parsed(/(?:\s[) (expr) \]/) { eval $whosit; } I may not be up-to-date on macros and is parsed, but ITYM: macro prefix:[ ($whosit) is parsed(/(Perl6.expr) \]/) { return eval $whosit; } This should return text, I believe. But the parser will not be expecting a term (or prefix:-operator) here ... it is looking for an infix:-operator or a postfix:-operator, right? (And it will eval() at compile time, so my phase-of-the-moon example will not be evaluated at run time, even if this works.) The macro immediately evaluates the expression, so it has to be a deferrable reference. Then: macro infix:eqn($n) is equiv (infix:eq) { [String::strncmp.assuming(n = 4)] } (s/4/\$n/, I believe.) But the infix:-operators by default get their LHS and RHS parse trees as parameters, last I heard, so your parameter list is too short. Still, you may be on to something ... what about this? macro infix:eqn ($lhs, $n, $rsh) is equiv(infix:eq) is parsed(/ \( (Perl6.expr) \) (Perl6.expr but speculatively_equiv(infix:eq))/) { return String::strncmp($lhs, ($rhs), ($n)); } if Dough eqn(4) Douglas {...} becomes if String::strncmp(Dough, (Douglas), (4)) {...} Okay, that may be evil. But it DWYW, right? No such luck with my phase-of-the-moon example, though. And come to think of it, finding the right precedence might be tricky, even if this (or more complicated re-parsing tricks) should happen to work: macro infix:[ ($lhs, Sub $op, $rhs) is equiv($op) is parsed(/(Perl6.expr) \] (Perl6.expr but speculatively_equiv($op))/) { return ($op).(($lhs), ($rhs)); } # This might be determinable at compile time: if $test [$moon.is_waxing ? infix: : infix:=] $target {...} # This would need explicit but equiv or something like that: if $test [($lookup{$key} || infix:eq) but equiv(infix:eq)] $target {...} So, probably just a bad idea. Eirik -- All bridge hands are equally likely, but some are more equally likely than others. -- Alan Truscott
Re: Pondering parameterized operators
[EMAIL PROTECTED] (Luke Palmer) writes: [$lhs, $rhs]æ\220\215.æ\235\237compile; What's that in old money? -- As the saying goes, if you give a man a fish, he eats for a day. If you teach him to grep for fish, he'll leave you alone all weekend. If you encourage him to beg for fish, pretty soon c.l.p.misc will smell like a three-week-dead trout. -- Tom Phoenix, c.l.p.misc.
Re: Pondering parameterized operators
Simon Cozens writes: [EMAIL PROTECTED] (Luke Palmer) writes: [$lhs, $rhs]\220\215.\235\237compile; What's that in old money? Eep. I thought I had mutt's utf-8 working, but apparently not. Does anyone who knows about these things want to mail me instructions, or something? That'd be nice for most everyone who reads my posts :-) Luke [$lhs, $rhs].compile;
Re: Pondering parameterized operators
Luke Palmer [EMAIL PROTECTED] writes: Cool stuff. In my usual pedantic sort of way, I'll go through the message and fix everything you said. For educational purposes only, of course :-) Thanks :-) For further education, some more questions/comments, if I may: # Let's say Cis parsed args come before the default infix args macro infix:[ ($op, $lhs, $rhs) is parsed( /:w (Perl6.expr) \]/ ) [snip] You shouldn't parse the right hand side yourself. That fixes the issue. I was not aware of this option. A6/E6 gave me the impression that Cis parsed would override the default parsing of the RHS, not merely augment it. Does the parsed-trait somehow interact with the signature of the macro, to find out whether to extend or replace? That is, can I write prefix:-macros that do not take the default RHS parameters, but only the ones generated by Cis parsed? Quotelike operators come to mind: macro prefix:qtex ($raw) is parsed( /(Perl6.delimited_balanced .*?)/ ) { ... } Or would that be accomplished by another keyword, indicating what, in the absence of Cis parsed, would be 0-ary? term:qtex, perhaps? I guess that depends upon what kind of consistency you are aiming for. Do you Iwant to give me a heart attack? :-/ Nope. I will try to restrain myself. This would be fine, I think: sub eqn ($n) { String::strncmp.assuming(n = $n) } You mean it would be fine for using with the infix:[ macro, right? But then you could not get the precedence you want. You would be stuck with whatever precedence infix:[ was given. Eirik -- All bridge hands are equally likely, but some are more equally likely than others. -- Alan Truscott
Re: Pondering parameterized operators
Luke Palmer [EMAIL PROTECTED] writes: Hmm, since we're requiring no whitespace between a variable and it's subscript, this should be possible: if Dough [eqn 4] Douglas {...} Lisp! :-) Well, almost. Now this would be lisp-y: if $test [$moon.is_waxing ? infix: : infix:=] $target {...} Let us see ... somewhat speculative and probably short-of-the-mark generalization coming up: macro infix:[ ($lhs, $op, $rhs) is parsed(/(Perl6.expr) \] (Perl6.expr)/) { return { $op($lhs, $rhs) }; } (Precedence? Err ... the left hand side has already been parsed, so infix:[ must be of fixed precedence to the left hand side, right? Damn, I thought I had it ...) Then vector operators, like +, are really just simple [vectorize infix:+] and similar -- except properly optimized and presumably with proper precedence. And, you can write: if Dough [String::strncmp.assuming(n = 4)] Douglas {...} Still long. Oh well. infix:[eqn, perhaps? At least that one will be of fixed precedence. Right? macro infix:[eqn ($lhs, $n, $rhs) is equiv(infix:eq) is parsed(/(Perl6.expr) \] (Perl6.expr but speculatively_equiv(infix:eq))/) { return { String::strncmp($lhs, $rhs, n = $n) }; } Eirik -- So this is the Sword of Immortality? Huh? What's it doin' in a CRYPT?! --- John S. Novak, III, quoting an unnamed player
RE: Pondering parameterized operators
-Original Message- From: Eirik Berg Hanssen [mailto:[EMAIL PROTECTED] Sent: Saturday, September 27, 2003 11:35 AM To: [EMAIL PROTECTED] Subject: Re: Pondering parameterized operators Luke Palmer [EMAIL PROTECTED] writes: Hmm, since we're requiring no whitespace between a variable and it's subscript, this should be possible: if Dough [eqn 4] Douglas {...} Lisp! :-) No, just horribly early evaluation. That'll do, Luke. That'll do. if $test [$moon.is_waxing ? infix: : infix:=] $target {...} This is right, presuming we have a way to give the parser the right data (function properties). Let us see ... somewhat speculative and probably short-of-the-mark generalization coming up: macro infix:[ ($lhs, $op, $rhs) is parsed(/(Perl6.expr) \] (Perl6.expr)/) { return { $op($lhs, $rhs) }; } (Precedence? Err ... the left hand side has already been parsed, so infix:[ must be of fixed precedence to the left hand side, right? Damn, I thought I had it ...) This is text replacement, not expression evaluation. You do have it from where I sit. # Note: Need a way to parse nested []'s macro [ ($whosit) is parsed(/(?:\s[) (expr) \]/) { eval $whosit; } The macro immediately evaluates the expression, so it has to be a deferrable reference. Then: macro infix:eqn($n) is equiv (infix:eq) { [String::strncmp.assuming(n = 4)] } so if Dough eqn(4) Douglas {...} becomes if Dough [sub String::strncmp.assuming(n = 4)] Douglas {...} becomes if Dough temporary infix-binary inserted by macro Douglas {...} and it just works. Woo-hoo! Then vector operators, like +, are really just simple [vectorize infix:+] and similar -- except properly optimized and presumably with proper precedence. And, you can write: if Dough [String::strncmp.assuming(n = 4)] Douglas {...} Still long. Oh well. infix:[eqn, perhaps? At least that one will be of fixed precedence. Right? See above. No precedence worries with an unattached macro -- do a text replacement or give the parser a correctly attributed tree, and let it worry about it. =Austin
Re: Pondering parameterized operators
Cool stuff. In my usual pedantic sort of way, I'll go through the message and fix everything you said. For educational purposes only, of course :-) Eirik Berg Hanssen writes: Luke Palmer [EMAIL PROTECTED] writes: Hmm, since we're requiring no whitespace between a variable and it's subscript, this should be possible: if Dough [eqn 4] Douglas {...} Lisp! :-) Well, almost. Now this would be lisp-y: if $test [$moon.is_waxing ? infix: : infix:=] $target {...} if $test [$moon.is_waxing ?? infix: :: infix:=] $target {...} Let us see ... somewhat speculative and probably short-of-the-mark generalization coming up: macro infix:[ ($lhs, $op, $rhs) is parsed(/(Perl6.expr) \] (Perl6.expr)/) { return { $op($lhs, $rhs) }; } Pretty close. # Let's say Cis parsed args come before the default infix args macro infix:[ ($op, $lhs, $rhs) is parsed( /:w (Perl6.expr) \]/ ) { my ($clhs, $crhs) = [$lhs, $rhs].compile; #only compile once return { $op($clhs.run, $crhs.run); } } This would have the precedence of infix:+ . (Precedence? Err ... the left hand side has already been parsed, so infix:[ must be of fixed precedence to the left hand side, right? Damn, I thought I had it ...) You shouldn't parse the right hand side yourself. That fixes the issue. Note that this is just how ??:: is going to do things: macro infix:?? ($iftrue, $cond, $iffalse) is parsed( /:w (Perl6.expr) '::'/ ) is tighter(infix:=) is assoc('right') { my ($ccond, $ciftrue, $iffalse) = [$iftrue, $cond, $iffalse].compile; return { if $ccond.run { $ciftrue.run; } else { $ciffalse.run; } } } And there might just be a Cis compiled trait to automatically do that first line. If not, it will surely be defined in Macro::Common. :-) Then vector operators, like +, are really just simple [vectorize infix:+] and similar -- except properly optimized and presumably with proper precedence. Yeah. Very cool. And, you can write: if Dough [String::strncmp.assuming(n = 4)] Douglas {...} Still long. Oh well. infix:[eqn, perhaps? Do you Iwant to give me a heart attack? :-/ This would be fine, I think: sub eqn ($n) { String::strncmp.assuming(n = $n) } At least that one will be of fixed precedence. Right? macro infix:[eqn ($lhs, $n, $rhs) is equiv(infix:eq) is parsed(/(Perl6.expr) \] (Perl6.expr but speculatively_equiv(infix:eq))/) { return { String::strncmp($lhs, $rhs, n = $n) }; } I can't feel my left arm... Again, you don't need to parse the right side of the operator yourself, otherwise it be a postfix: macro. Luke
Pondering parameterized operators
So I sit here and think for a minute about how nice it will be in P6 to be able to define operator infix:eqi($str1, $str2) {...} for doing if ($1 eqi last) and I think about the whole 'C' string library. Which dredges up my old questions about parameterized operators: How can I conveniently pass an extra parameter to a historically binary operator? At one point, the colon was going to do that, but Larry took it back: if (Dough eqn:4 Douglas) # true { ... The options left seem to be: package String; sub strncmp($a, $b, $n) {...} package main; sub infix:immed String::strncmp.assuming($n = 4); if (Dough immed Douglas) # ? or: class InfixBinary is Code {...} # How do I create a type? -- I want to define a return-type-spec # that just guarantees context behavior. sub eqn($max) returns InfixBinary { return String::strncmp.assuming($n=$max); } if (Dough eqn(4) Douglas) ... Frankly, I like the second one. =Austin
Re: Pondering parameterized operators
On Fri, 26 Sep 2003, Austin Hastings wrote: How can I conveniently pass an extra parameter to a historically binary operator? If it's one of the 'base' binary operators (addition, subtraction, and whatnot) you don't. Dan
Re: Pondering parameterized operators
Austin Hastings writes: How can I conveniently pass an extra parameter to a historically binary operator? I see a few possibilities. The first, call it like a function: if infix:eqn(Dough, Douglas, n = 4) {...} Or, you could use the adverbial modifier Cwhere (well, not officially yet, but I hope so): if Dough eqn Douglas where n=4 {...} But that has some problems, like putting the operator parameters really far away from the operator, and forcing parentheses on a function call on the right (lest the Cwhere be associated with the call). More below. At one point, the colon was going to do that, but Larry took it back: if (Dough eqn:4 Douglas) # true { ... The options left seem to be: package String; sub strncmp($a, $b, $n) {...} package main; sub infix:immed String::strncmp.assuming($n = 4); You probably mean: our infix:immed ::= String::strncmp.assuming($n = 4); if (Dough immed Douglas) # ? or: class InfixBinary is Code {...} # How do I create a type? -- I want to define a return-type-spec # that just guarantees context behavior. sub eqn($max) returns InfixBinary { return String::strncmp.assuming($n=$max); } if (Dough eqn(4) Douglas) ... Frankly, I like the second one. Yeah, I don't think it's a bad idea. I think returning an infix operator is not the way to go about it. Perhaps optional (and named) parameters on an infix operator could be taken from a parameter list: sub infix:eqn ($a, $b, ?$n) { substr($a, 0, $n) eq substr($b, 0, $n) } if Dough eqn(4) Douglas {...} That's not terribly good at making different things look different. It's pretty common to see parenthesized expressions on either side of an operator. Hmm, since we're requiring no whitespace between a variable and it's subscript, this should be possible: if Dough [eqn 4] Douglas {...} If we're going that far... sub foo($a, $b) { print $($a)y$b; } Dough [foo] Douglas; # DoughyDouglas Not sure I like that too well. Luke
Re: Pondering parameterized operators
Austin Hastings [EMAIL PROTECTED] wrote if (Dough eqn(4) Douglas) ... I wonder if the . operator is available here: if Dough eq.n(4) Douglas { ... } that makes it intuitive how to define new equality methods. One thing of concern is that we'd need whitespace rules to disambiguate things. I sense some wonderful opportunities for obfuscation. Dave.