Patterns
I propose that we remove the following two lines from the smart match table in S03: HashAny hash entry existence exists $_{$x} Array Any array contains item* any($_) === $x These are the two lines with Any on the right side. I want to remove these so that we can have an extensible ~~ operator. You can think of $x ~~ $y as saying $x matches $y, i.e. $y is some data pattern and we are asking if $x conforms to it. I want to be able to add my own kinds of patterns, and entries with Any in the right side undermine this. Why? Let's say I created a pattern which implemented another textual matcher alongside Perl's regexes, which was more convenient for some things (I shouldn't have to convince you that this is possible and useful). Let's call it Irregex. I want it to work just like Perl's regexes; i.e. I want it so that if you ask whether an array matches it, it will match against the elements of the array as though they were characters. So I just overload ~~ to work on (Array, Irregex) and that overrules (Array, Any) so there is no MMD ambiguity. However! Let's say I'm using a payroll library (or something, sorry for the mundane examples; I'm trying to keep it realistic) which sends a notification if any user's status matches a pattern, and it is implemented like so: method notify(Any|Junction $pattern) { if @.users.status ~~ $pattern { # send notification } } This is perfectly fine, elegant code given the ~~ table. But it breaks since we have added our new pattern type! It doesn't check if any user's status matches, it checks if the users' statuses' concatenated considered as atoms matches, totally wrong! So, I'm essentially asking for ~~ to be singly-dispatched based on its right argument, which gets to pick how to interpret the left one. In order to encourage this usage, I propose a design like so: role Pattern { method match($item) {...} } # Code, Bool, Undef, Whatever, Num, Junction, Str, Hash, ... ... all do Pattern sub *infix:~~ ($item, Pattern $pat) { $pat.match($item); } So to add a new pattern, you just implement the Pattern role, and you are safe. If you are very attached do those two rows of the smart match table, we can reimplement them as Pattern objects, at the expense of some unreadability: given @array { when 42 { ... } } Becomes: given @array { when contains 42 { ... } } etc. Luke
Re: Patterns
On Fri, Jan 05, 2007 at 08:47:18PM +, Luke Palmer wrote: : I propose that we remove the following two lines from the smart match : table in S03: : :HashAny hash entry existence exists $_{$x} :Array Any array contains item* any($_) === $x : : These are the two lines with Any on the right side. I want to remove : these so that we can have an extensible ~~ operator. : : You can think of $x ~~ $y as saying $x matches $y, i.e. $y is some : data pattern and we are asking if $x conforms to it. I want to be : able to add my own kinds of patterns, and entries with Any in the : right side undermine this. It's much worse than just those two entries, because any entry not marked with * is currently considered reversible. However, I think you're the path toward sanity. : Why? Let's say I created a pattern which implemented another textual : matcher alongside Perl's regexes, which was more convenient for some : things (I shouldn't have to convince you that this is possible and : useful). Let's call it Irregex. I want it to work just like Perl's : regexes; i.e. I want it so that if you ask whether an array matches : it, it will match against the elements of the array as though they : were characters. So I just overload ~~ to work on (Array, Irregex) : and that overrules (Array, Any) so there is no MMD ambiguity. : : However! Let's say I'm using a payroll library (or something, sorry : for the mundane examples; I'm trying to keep it realistic) which sends : a notification if any user's status matches a pattern, and it is : implemented like so: : :method notify(Any|Junction $pattern) { :if @.users.status ~~ $pattern { :# send notification :} :} : : This is perfectly fine, elegant code given the ~~ table. But it : breaks since we have added our new pattern type! It doesn't check if : any user's status matches, it checks if the users' statuses' : concatenated considered as atoms matches, totally wrong! I'm not so worried about extensibility as I am about consistency between compile time and run time, such that the optimizer can optimize without surprising the user. But this also argues against any anonymous Any on the right. If all the when expressions are Num, the optimizer wants to be able to evaluate the given in a numeric context whether or not you put + on the front of it. : So, I'm essentially asking for ~~ to be singly-dispatched based on its : right argument, which gets to pick how to interpret the left one. In : order to encourage this usage, I propose a design like so: : :role Pattern { :method match($item) {...} :} :# Code, Bool, Undef, Whatever, Num, Junction, Str, Hash, ... ... : all do Pattern : :sub *infix:~~ ($item, Pattern $pat) { :$pat.match($item); :} One little problem here is that .match is currently defined the reverse of that for the method form of m//. : So to add a new pattern, you just implement the Pattern role, and you are : safe. : : If you are very attached do those two rows of the smart match table, : we can reimplement them as Pattern objects, at the expense of some : unreadability: : :given @array { :when 42 { ... } :} : : Becomes: : :given @array { :when contains 42 { ... } :} : : etc. Rather than special casing array matching, I'd say we want a general form for explicitly reversing the figure/ground. If .match demands a pattern on the left, then given @array { when .match(42) {...} } will already reverse the test to mean 42 ~~ @array. As I say, we need to figure out what to do with foo.match(/bar/) though. Larry
Re: Patterns
At the moment I'm leaning toward: $pattern.accepts($thing) $pattern.rejects($thing) and going the other way $thing ~~ $pattern $thing.match($pattern) $thing.subst($pattern) and most generally, something like: $thing.does($pattern) $thing.when($pattern) By the way, the Pattern type is already called Selector in the synopses. Or perhaps Selector is a bit more general. Arguably Pattern is the role that defines .accepts and .rejects, but Selector is really the Pattern|Junction type you use in a signature. But we can't just have Pattern does Junction or everything turns into a junction. :/ Or maybe they should be the other way around, where Selector is the role and Pattern is the sig type. Or maybe the sig type should be Where so we can say multi grep (Where $where, [EMAIL PROTECTED]) {...} and call it with :where{...} or where = {...}. Selector is kind of a stupid name in any event. Anyway, that gives us: given $pattern { when .accepts(42) {...} } which given typical usage patterns of switch statements is probably adequately huffmanized, unless we want to go for something shorter than accepts/rejects, like acc/rej pix/nix ok/bogus Of course, all of the .rejects() variants could simply be spelled .accepts().not, but that seem unnecessarily cruel. Larry