Re: How to make a new operator.
At least in #perl6 I've never seen anybody try to write an auto-deduced sequence, and fail because of floating-point errors. Except for Martin's 1, sqrt(2), 2...8 But, yes, the widespread use of Rats rather than Nums means only the edgiest of edge-cases fails. And as you get an explicit Failure when it does happen, at least people will know when the numerical computations don't work as hoped. Damian
Re: Floating-point equality (was Re: How to make a new operator.)
On 03/25/2012 06:55 AM, Moritz Lenz wrote: I don't know if the majority of the perl6-language posters have realized it yet, but both Perl 6 and the its implementations are quite mature these days. Mature enough that such proposals should be prototyped as modules, and thoroughly tested on lots of existing code before taken into consideration for ... inclusion into the spec. Sometimes I do finish my sentences with several hours delay, sorry for that. Cheers, Moritz
Re: Not-so-smart matching (was Re: How to make a new operator.)
I also like agreement, conformance... In a situation like this, I reach for a thesaurus- very useful when looking for just the right name for a variable/method name/way to describe a concept. Here's a grab bag to start with: accord, agree, conformance, conformation, conformity, congruence, congruity, consensus, consonance, correspondence, harmony, unison agree, fit, correspond, compeer, meet, gibe, pair, mate, twin, cope with, touch Fit, correspond, congruity, harmonize seem like other good descriptions for the concept. Fit is especially good due to its brevity, and congruence is good due to the use of ~~ as the smartmatch aka congruence/fitness/agreement/harmonizing/correspondence/conformance operator. (Bikeshed?) -y On Sun, Mar 25, 2012 at 12:35 AM, David Green david.gr...@telus.net wrote: On 2012-March-21, at 6:38 pm, Daniel Carrera wrote: The idea of smart-matching a function just doesn't quite fit with my brain. I can memorize the fact that smart-matching 7 and foo means evaluating foo(7) and seeing if the value is true, but I can't say I understand it. Maybe it just needs a better name. Match implies that two (or more) things are being compared against each other, and that's how smart-matching started out, but it's been generalised beyond that. The underlying .ACCEPTS method suggests acceptance... but that's too broad (a function can accept args without returning true). Agreement fits, in the sense of that [food] agrees with me, but I think it suggests equality a bit too strongly. Accordance? Conformance? Validation? That seems a good match (ahem) for the concept: ~~ checks whether some value is valid (or desired?) according to certain criteria. The obvious way to validate some value against a simple string or number is to compare them; or against a pattern, to see if the value matches; but given a function, you check the value by passing it to the function and seeing whether it says yea or nay. I'm not sure validation or validity is the best name, but it conforms better to what smart-matching does. Or conformance Hm. But terminology that sets up the appropriate expectations is a good thing. -David
Re: Not-so-smart matching (was Re: How to make a new operator.)
yary suggested: In a situation like this, I reach for a thesaurus The standout from that list for me is: 'consonance'. Second favorite is: 'gibe' or 'jibe'. But the underlying operation is .ACCEPTS(), so perhaps the operation should be referred to as acceptance or acceptibility. Damian
Re: How to make a new operator.
On Fri, Mar 23, 2012 at 07:14:51PM +1100, Damian Conway wrote: : For example: : : 1, 1.0001, 1.0002 ... * : : won't deduce a correct arithmetic sequence either (on most hardware). Actually, that one works fine in both niecza and rakudo, since those are Rats. Larry
Re: How to make a new operator.
Actually, that one works fine in both niecza and rakudo, since those are Rats. Oh, that's good to hear. It doesn't change my underlying argument however. Any operations performed on genuine floats are going to lose precision, and if we're using such operations to infer relationships (such as equality or sequence) then we ought to take the loss of precision we're causing into account when deciding outcomes. Which seems to mean either (a) making it a compiletime error to request sequence inferences on floats , or (b) comparing the differences and quotients within the sequence inference with a larger epsilon (or using interval arithmetic). Damian
Floating-point equality (was Re: How to make a new operator.)
On 2012-March-23, at 12:01 am, Damian Conway wrote: [...] we ought to allow for the inevitable loss of significant digits within the two preliminary division ops, and therefore compare the results with an suitably larger epsilon. That would not only be computational more justifiable, I suspect it might also produce more least surprise. ;-) I think that comparisons for floating-point values should take some kind of 'significance' adverb and complain if it's missing. Having to be explicit makes for the least surprise of all. π == 22/7 # error π == 22/7 :within(0.002)# true π == 22/7 :within(0.2) # false Probably with something like 'use epsilon :within(0.0002)' as way to declare the fuzziness for a given scope if you have a lot of comparisons. And of course you could use (the equivalent of) 'use epsilon :within(0)' to say, I know what I'm doing, just give me straight what I ask for and I'll take the consequences. Alternatively, maybe have float-comparisons give an error or warning, and introduce an approximation operator: π == ~22/7 :within($epsilon). (Except ~ is already taken!) [I was going to suggest that as a way to handle stopping points in a sequence: 1, 3, 5 ... ~10, but that still wouldn't work without treating the Num::Approx values as a special case, which defeats the purpose. Though with a postfix up from operator, you could say: 1, 3, 5 ... 10^.] -David
Not-so-smart matching (was Re: How to make a new operator.)
On 2012-March-21, at 6:38 pm, Daniel Carrera wrote: The idea of smart-matching a function just doesn't quite fit with my brain. I can memorize the fact that smart-matching 7 and foo means evaluating foo(7) and seeing if the value is true, but I can't say I understand it. Maybe it just needs a better name. Match implies that two (or more) things are being compared against each other, and that's how smart-matching started out, but it's been generalised beyond that. The underlying .ACCEPTS method suggests acceptance... but that's too broad (a function can accept args without returning true). Agreement fits, in the sense of that [food] agrees with me, but I think it suggests equality a bit too strongly. Accordance? Conformance? Validation? That seems a good match (ahem) for the concept: ~~ checks whether some value is valid (or desired?) according to certain criteria. The obvious way to validate some value against a simple string or number is to compare them; or against a pattern, to see if the value matches; but given a function, you check the value by passing it to the function and seeing whether it says yea or nay. I'm not sure validation or validity is the best name, but it conforms better to what smart-matching does. Or conformance Hm. But terminology that sets up the appropriate expectations is a good thing. -David
Re: How to make a new operator.
On 03/23/2012 09:14 AM, Damian Conway wrote: it means we cannot do the same fuzziness for the endpoint, Except that we will be encouraging people to use: * = $END as their standard endpoint pattern, which will provide most of the necessary fuzz. and which will still surprise those people who are surprised by floating point inaccuracies. This discussion makes me think that maybe deducing geometric sequences is too much magic as well. Geometric sequence inference is fine on Ints and Rats. But, if we can't perform inferences involving Nums in a sound numerical way (and it may well be that we can't, without taking a noticeable performance hit), then I think that we would be better off limiting the deduction of *both* arithmetic and geometric sequences to starting lists that contain only Ints and Rats. Floating point numbers *can* represent a huge number of commonly used values without errors, and you can do error-free arithmetic operations on many of them. Excluding Nums from automatic deduction feels like an unnecessary pessimization or stigmatization, especially if you consider that writing a number like 0.001 in your program gives a Rat by default not a Num. Most of the time you only get a Num in Perl 6 if you consciously decide to write one, in which case you should also be well aware of the limitations of FP math. At least in #perl6 I've never seen anybody try to write an auto-deduced sequence, and fail because of floating-point errors. Cheers, Moritz
Re: Floating-point equality (was Re: How to make a new operator.)
On 03/25/2012 05:59 AM, David Green wrote: On 2012-March-23, at 12:01 am, Damian Conway wrote: [...] we ought to allow for the inevitable loss of significant digits within the two preliminary division ops, and therefore compare the results with an suitably larger epsilon. That would not only be computational more justifiable, I suspect it might also produce more least surprise. ;-) I think that comparisons for floating-point values should take some kind of 'significance' adverb and complain if it's missing. Having to be explicit makes for the least surprise of all. π == 22/7 # error π == 22/7 :within(0.002)# true π == 22/7 :within(0.2) # false Note that neither 22/7 nor 0.002 are floating-point values. I don't know if the majority of the perl6-language posters have realized it yet, but both Perl 6 and the its implementations are quite mature these days. Mature enough that such proposals should be prototyped as modules, and thoroughly tested on lots of existing code before taken into consideration for Niecza supports operator adverbs, and supports them on user-defined operators, so there's nothing to stop you from trying it. Cheers, Moritz
Re: How to make a new operator.
Patrick correctly observed: On Rakudo on my system, sqrt(2) indeed produces a Num, but since floating point arithmetic doesn't result in sqrt(2) / 1 == 2 / sqrt(2), no geometric sequence is deduced and the sequence fails with unable to deduce sequence. Although, arguably, that might be considered a bug. Not that sqrt(2) / 1 should == 2 / sqrt(2) of course, but that, when deducing a sequence we know we're comparing quotients, so we ought to allow for the inevitable loss of significant digits within the two preliminary division ops, and therefore compare the results with an suitably larger epsilon. That would not only be computational more justifiable, I suspect it might also produce more least surprise. ;-) Damian
Re: How to make a new operator.
On 03/23/2012 07:01 AM, Damian Conway wrote: Patrick correctly observed: On Rakudo on my system, sqrt(2) indeed produces a Num, but since floating point arithmetic doesn't result in sqrt(2) / 1 == 2 / sqrt(2), no geometric sequence is deduced and the sequence fails with unable to deduce sequence. Although, arguably, that might be considered a bug. Not that sqrt(2) / 1 should == 2 / sqrt(2) of course, but that, when deducing a sequence we know we're comparing quotients, so we ought to allow for the inevitable loss of significant digits within the two preliminary division ops, and therefore compare the results with an suitably larger epsilon. That would not only be computational more justifiable, I suspect it might also produce more least surprise. ;-) But unless we twist smartmatching semantics for that purpose, it means we cannot do the same fuzziness for the endpoint, condemning people to write infinite loops instead of failing fast. So I'm firmly against such magic. All the previous iterations of the sequence operator had some additional degrees of magic, and we've come to regret all of them. This discussion makes me think that maybe deducing geometric sequences is too much magic as well. Cheers, Moritz
Re: How to make a new operator.
On 03/23/2012 05:30 AM, Patrick R. Michaud wrote: On Fri, Mar 23, 2012 at 03:03:09PM +1300, Martin D Kealey wrote: Question: do we support 1, 2i, -4 ... 256 I think this ought to work, but for some reason Rakudo on my system hangs whenever I try it. The problem was that infix:!= hung with Complex numbers, because it was defined for each numeric type, but the Complex candidate was missing. Thus the most general candidate called .Numeric on its arguments, re-dispatched, and looped infinitely. Fixed in 2012.03-3-g4a247b1, and tested in S32-num/complex.t. This also fixes the sequence 1, 2i, -4 ... 256. Cheers, Moritz
Re: How to make a new operator.
But unless we twist smartmatching semantics for that purpose, No! Please, no. ;-) it means we cannot do the same fuzziness for the endpoint, Except that we will be encouraging people to use: * = $END as their standard endpoint pattern, which will provide most of the necessary fuzz. So I'm firmly against such magic. But that's the point: it's not magic. It's correct numerical computation under the limitations of floating-point arithmetic. As discussed in every numerical computing textbook for the last half a century. Note that this problem occurs for *arithmetic* deductions as well. If either number is floating point, some loss of precision in the difference between them is almost inevitable, especially if the two numbers are very close. For example: 1, 1.0001, 1.0002 ... * won't deduce a correct arithmetic sequence either (on most hardware). In fact that example would be slightly more likely to imply a geometric sequence, since a division operation loses fewer significant digits than a subtraction when the arguments are both so close to 1.0) This discussion makes me think that maybe deducing geometric sequences is too much magic as well. Geometric sequence inference is fine on Ints and Rats. But, if we can't perform inferences involving Nums in a sound numerical way (and it may well be that we can't, without taking a noticeable performance hit), then I think that we would be better off limiting the deduction of *both* arithmetic and geometric sequences to starting lists that contain only Ints and Rats. Damian
Re: How to make a new operator.
On Thu, Mar 22, 2012 at 11:07:08AM -0500, Bruce Gray wrote: Well, it works in Niecza. It does not (yet) work in Rakudo: 15:25 Util perl6: my @squares := 0, (- *@a { @a.elems ** 2 }) ... *; say ~@squares[^11]; 15:25 p6eval ..niecza v15-4-g1f35f89: OUTPUT0 1 4 9 16 25 36 49 64 81 100NL 15:25 p6eval ..rakudo 1a468d: OUTPUT0 0 0 0 0 0 0 0 0 0 0NL It now works in Rakudo, as of 2012.03-5-g69920db: my @squares = 0, (- *@a { @a.elems ** 2 }) ... *; say @squares[^11]; 0 1 4 9 16 25 36 49 64 81 100 Also @_ now DTRT again: my @squares = { @_ ** 2 } ... *; say @squares[^11]; 0 1 4 9 16 25 36 49 64 81 100 my @triangle = 1, { @_[*-1] + @_ + 1 } ... *; say @triangle[^11] 1 3 6 10 15 21 28 36 45 55 66 Note that Rakudo also doesn't require a binding operation for the array... assignment of detectably infinite lists (indicated here by the final Whatever term) is supported. Pm
Re: How to make a new operator.
On 22 March 2012 04:59, Jonathan Lang datawea...@gmail.com wrote: My understanding is if you want to count by threes, starting at 2 and ending at 14, you should be able to write: 2, 5 ... 14 That certainly looks very intuitive, and it is similar to what I would write in an email. The only annoyance is that I have to do a bit of mental arithmetic. But I guess that's ok. Especially since most of the time you'd probably want to write 2,5...* anyway. So: 1, 3 ... 13 # same as 1,3,5,7,9,11,13 1 ... 10 # same as 1,2,3,4,5,6,7,8,9,10 1, 2, 4 ... 100 # same as 1,2,4,8,16,32,64 That last one doesn't work on Rakudo :-( Meanwhile, using Whatever for the test condition means keep the series going indefinitely: 1, 3 ... * # every positive odd number. 1 ... * # all counting numbers. 1, 2, 4 ... * # all powers of 2. Yeah, and those are very convenient. And using '...^' instead of '...' changes the default final test condition from ' $n' to '= $n': 1, 3 ...^ 13 # same as 1,3,5,7,9,11 1 ...^ 10 # same as 1,2,3,4,5,6,7,8,9 1, 2, 4 ...^ 100 # same as 1,2,4,8,16,32,64 Ok. I hadn't thought of doing that. In short, what Damian is talking about is the more powerful and reliable use of the syntax; but the above approach (assuming it has been properly implemented) is a more intuitive use that covers the most common cases. Make common things easy, and make uncommon things possible. Yeah. Likewise, using Whatever in conjunction with operators is there to provide an intuitive way to calculate the next term from the previous one(s): 1, *+2 ... 13 # start at 1, step by 2s, stop at 13. 1, 1, *+* ... * # each new term is the sum of the previous two. Oh! That second one is cool. a one line implementation of the Fibonacci sequence. Cheers, Daniel. -- I'm not overweight, I'm undertall.
Re: How to make a new operator.
Jonathan Lang (), Daniel (): So: 1, 3 ... 13 # same as 1,3,5,7,9,11,13 1 ... 10 # same as 1,2,3,4,5,6,7,8,9,10 1, 2, 4 ... 100 # same as 1,2,4,8,16,32,64 That last one doesn't work on Rakudo :-( And it never will. Note that 100 is not a power of 2, and that the goal needs to match exactly. This is because smartmatching is used, not some other comparison. The sequence will continue to generate numbers until the number 100 is generated, which never happens. Rakudo loops forever on this one, as per spec. If you're wondering why things are factored in this way, it's because previous versions of the spec that tried to special-case 100 to work in cases like the above, ended up not working out. It turned out that the unification of infix:... and smartmatching was what did work. It has the slight drawback that we have to educate users to write * = 100 instead of 100 in the case of not-exactly-matching goal states. But it's still a net win, because this unified semantics works better than anything we had before. // Carl
Re: How to make a new operator.
On 22 March 2012 11:02, Carl Mäsak cma...@gmail.com wrote: 1, 2, 4 ... 100 # same as 1,2,4,8,16,32,64 That last one doesn't work on Rakudo :-( And it never will. Note that 100 is not a power of 2, and that the goal needs to match exactly. This is because smartmatching is used, ... If you're wondering why things are factored in this way, it's because previous versions of the spec that tried to special-case 100 to work in cases like the above, ended up not working out. It turned out that the unification of infix:... and smartmatching was what did work. It has the slight drawback that we have to educate users to write * = 100 instead of 100 in the case of not-exactly-matching goal states. But it's still a net win, because this unified semantics works better than anything we had before. But that's a bit of a problem if I *don't* want a value higher than 100. 2,4,8... * = 100 2 4 8 16 32 64 128 There is no simple formula I can use at the end to get the sequence to stop where I want. So I have to do something like: my @a = 2,4,8... * = 100; @a.pop # Use @a Cheers, Daniel. -- I'm not overweight, I'm undertall.
Re: How to make a new operator.
On 03/22/2012 11:51 AM, Daniel Carrera wrote: On 22 March 2012 11:02, Carl Mäsak cma...@gmail.com wrote: 1, 2, 4 ... 100 # same as 1,2,4,8,16,32,64 That last one doesn't work on Rakudo :-( And it never will. Note that 100 is not a power of 2, and that the goal needs to match exactly. This is because smartmatching is used, ... If you're wondering why things are factored in this way, it's because previous versions of the spec that tried to special-case 100 to work in cases like the above, ended up not working out. It turned out that the unification of infix:... and smartmatching was what did work. It has the slight drawback that we have to educate users to write * = 100 instead of 100 in the case of not-exactly-matching goal states. But it's still a net win, because this unified semantics works better than anything we had before. But that's a bit of a problem if I *don't* want a value higher than 100. Then exclude it: 2, 4, 8 ...^ * 100 Cheers, Moritz
Re: How to make a new operator.
On 22 March 2012 12:06, Moritz Lenz mor...@faui2k3.org wrote: But that's a bit of a problem if I *don't* want a value higher than 100. Then exclude it: 2, 4, 8 ...^ * 100 Ok... I looked up what you did. I see how it works. Thanks. Related questions: What types of sequences can Perl 6 recognize? -- I'm not overweight, I'm undertall.
Re: How to make a new operator.
Daniel (): Related questions: What types of sequences can Perl 6 recognize? As covered by Jonathan Lang earlier in this thread (though it was perhaps easy to miss), Perl 6 auto-detects arithmetic sequences (same additive difference each time) and geometric sequences (same multiplicative factor applied each time). Two terms are enough to seed the first kind; three terms are necessary for the second kind. If you supply three terms that follow neither an arithmetic or a geometric sequence (and doesn't contain a Callable as its last term), Perl 6 throws up its hands and doesn't try to guess. If you ask me, auto-detecting arithmetic and geometric sequences, but nothing else, is pretty much the sweet spot. We don't want to put more in CORE. The one that comes up most often as a suggested addition is the sequence of primes. Mostly just to mess with people who try it. :-) // Carl
Re: How to make a new operator.
On Mar 21, 2012, at 11:49 PM, Jonathan Lang wrote: What I want to know is whether there's a way to define a step function that's based in part or in whole on the current term's index. For example, how would I use infix:... to generate the perfect squares between 0 and 100? Namely, '0,1,4,9,16,25,36,49,64,81,100'. For example, is Perl 6 set up to try to pass the current element's index into the step function by means of a named parameter? I would hope for something like: - :index { $index * $index } ... 100 or 1, *+:index ... * # 1,3,6,10,15,21,28,36,45,... (Note: I _don't_ expect the above to work as is; they're merely intended to convey a rough idea of what I _do_ want.) If not, how _would_ I generate these lists? In real life, you would just use this: my @squares = map { $_ * $_ }, 0..10; or, for an infinite list, use a binding instead of an assignment: my @squares := map { $_ * $_ }, 0..*; But you were asking about ... specifically :^) I have run into the same need for something like :index, while playing with RosettaCode tasks like Continued_fraction. Your squares example will be clearer than the RC tasks. At first, I tried to trick the compiler, by *binding* the list to an array, then referring to that bound array from within the closure. my @squares := 0, { @squares.elems ** 2 } ... *; This worked, but only as an artifact of the then-current Rakudo implementation. It is not specced to work, and I was told in freenode/#perl6 not to rely on that behavior. On freenode/#perl6, I was pointed to part of the spec that I had overlooked. The sequence operator is defined in S03: http://perlcabal.org/syn/S03.html#List_infix_precedence Buried in its definition is this gem: http://perlcabal.org/syn/S03.html#line_1884 The function may also be slurpy (n-ary), in which case all the preceding values are passed in (which means they must all be cached by the operator, so performance may suffer, and you may find yourself with a space leak). That means that this will work: sub sq_gen (*@a) { @a.elems ** 2 }; my @squares = 0, sq_gen ... {$_ = 100}; say ~@squares; (Note that the asterisk in *@a is mandatory) or, infinitely: sub sq_gen (*@a) { @a.elems ** 2 }; my @squares := 0, sq_gen ... *; say ~@squares[^11]; Great! However, I wanted to do it inline, without a separately-defined sub. If it wasn't for that required asterisk, then I could use a placeholder variable to do this: my @squares = 0, { @^a.elems ** 2 } ... {$_ = 100}; FAIL! (Niecza) Unhandled exception: Nominal type check failed in binding '@a' in 'ANON'; got Int, needed Positional The last piece of the puzzle is the arrow sub syntax, more commonly seen in for loops: my @squares = 0, (- *@a { @a.elems ** 2 }) ... {$_ = 100}; Or, more concisely: my @squares = 0, - *@a { +@a ** 2 } ... * = 100; This works! Well, it works in Niecza. It does not (yet) work in Rakudo: 15:25 Util perl6: my @squares := 0, (- *@a { @a.elems ** 2 }) ... *; say ~@squares[^11]; 15:25 p6eval ..niecza v15-4-g1f35f89: OUTPUT0 1 4 9 16 25 36 49 64 81 100NL 15:25 p6eval ..rakudo 1a468d: OUTPUT0 0 0 0 0 0 0 0 0 0 0NL For your second example (1,3,6,10,15,21,28,36,45,...), it would look like this: my @triangle = 1, (- *@a { @a[*-1] + @a.elems + 1 }) ... {$_ = 45}; Note that this particular sequence is just the triangle numbers, which has a shorter form via triangular reduce: my @triangle = [\+] 1..9; After writing all the above, it occurred to me that the use of @_ should implicitly define a closure as slurpy/n-ary. That would remove the need for the arrow, and make the code much less ugly. Also, the first value (0) might be unnecessary. The spec says that it should not be required when the closure is 0-ary, but I think that should also be true for slurpy/n-ary closures. These work in Niecza: my @squares := { @_ ** 2 } ... *; my @triangle := 1, { @_[*-1] + @_ + 1 } ... *; -- Hope this helps, Bruce Gray (Util of PerlMonks)
Re: How to make a new operator.
On Thu, Mar 22, 2012 at 9:07 AM, Bruce Gray bruce.g...@acm.org wrote: On Mar 21, 2012, at 11:49 PM, Jonathan Lang wrote: What I want to know is whether there's a way to define a step function that's based in part or in whole on the current term's index. For example, how would I use infix:... to generate the perfect squares between 0 and 100? Namely, '0,1,4,9,16,25,36,49,64,81,**100'. For example, is Perl 6 set up to try to pass the current element's index into the step function by means of a named parameter? I would hope for something like: - :index { $index * $index } ... 100 or 1, *+:index ... * # 1,3,6,10,15,21,28,36,45,... (Note: I _don't_ expect the above to work as is; they're merely intended to convey a rough idea of what I _do_ want.) If not, how _would_ I generate these lists? In real life, you would just use this: my @squares = map { $_ * $_ }, 0..10; or, for an infinite list, use a binding instead of an assignment: my @squares := map { $_ * $_ }, 0..*; True enough. But you were asking about ... specifically :^) Yes, I was. On freenode/#perl6, I was pointed to part of the spec that I had overlooked. The sequence operator is defined in S03: http://perlcabal.org/syn/S03.**html#List_infix_precedencehttp://perlcabal.org/syn/S03.html#List_infix_precedence Buried in its definition is this gem: http://perlcabal.org/syn/S03.**html#line_1884http://perlcabal.org/syn/S03.html#line_1884 The function may also be slurpy (n-ary), in which case all the preceding values are passed in (which means they must all be cached by the operator, so performance may suffer, and you may find yourself with a space leak). Interesting; it never occurred to me to try to retrieve the current index by slurping in all of the previous elements and counting them. After writing all the above, it occurred to me that the use of @_ should implicitly define a closure as slurpy/n-ary. That would remove the need for the arrow, and make the code much less ugly. Also, the first value (0) might be unnecessary. The spec says that it should not be required when the closure is 0-ary, but I think that should also be true for slurpy/n-ary closures. Agreed: starting values should only be mandatory when dealing with a step function that definitely requires them. These work in Niecza: my @squares := { @_ ** 2 } ... *; And this is rather elegant, syntactically (though not so much in the performance department). -- Jonathan Dataweaver Lang
Re: How to make a new operator.
Am 22.03.2012 17:07, schrieb Bruce Gray: I have run into the same need for something like :index, while playing with RosettaCode tasks like Continued_fraction. If you want the index, don't use series. It's easy enough to access the array elements yourself. You can do something like my @a := (1..*).map: - $i { $i ** 2 + @a[$i - 1] // 0; }; to access previous elements. You can even use 'last' inside the map block to get out of the loop. Well, it works in Niecza. It does not (yet) work in Rakudo: 15:25 Util perl6: my @squares := 0, (- *@a { @a.elems ** 2 }) ... *; say ~@squares[^11]; 15:25 p6eval ..niecza v15-4-g1f35f89: OUTPUT0 1 4 9 16 25 36 49 64 81 100NL 15:25 p6eval ..rakudo 1a468d: OUTPUT0 0 0 0 0 0 0 0 0 0 0NL higher-arity sequences are a known regression in rakudo, S03-sequence/limit-arity-2-or-more.t currently isn't run. After writing all the above, it occurred to me that the use of @_ should implicitly define a closure as slurpy/n-ary. It shouldn't only, it does already (in all rakudo pugs niecza). The future is already here, it's just unevenly distributed. Cheers, Moritz
Re: How to make a new operator.
On Thu, 22 Mar 2012, Carl Mäsak wrote: Jonathan Lang (), Daniel (): 1, 2, 4 ... 100 # same as 1,2,4,8,16,32,64 That last one doesn't work on Rakudo :-( And it never will. Note that 100 is not a power of 2, and that the goal needs to match exactly. This is because smartmatching is used, not some other comparison. The sequence will continue to generate numbers until the number 100 is generated, which never happens. Rakudo loops forever on this one, as per spec. Hmmm, so it's likely that most times you get a Num rather than an Int or Rat, those won't stop either? 1, 7 / 6.0 ... 2 1, sqrt(2), 2 ... 8 Question: do we support 1, 2i, -4 ... 256 If you're wondering why things are factored in this way, it's because previous versions of the spec that tried to special-case 100 to work in cases like the above, ended up not working out. It turned out that the unification of infix:... and smartmatching was what did work. It has the slight drawback that we have to educate users to write * = 100 instead of 100 in the case of not-exactly-matching goal states. But it's still a net win, because this unified semantics works better than anything we had before. Sounds to me like AscendingArithmeticIteratorInclusiveTerminalSmartMatch could do the same thing as normal SmartMatch except when the LHS is an IteratorOf{X} and the RHS is an {X}, for X in {Int, Rat, Num} and possibly other comparable (orderable) types, when would be implied. Likewise for AscendingArithmeticIteratorExclusiveTerminalSmartMatch (=) DescendingArithmeticIteratorInclusiveTerminalSmartMatch () and DescendingArithmeticIteratorExclusiveTerminalSmartMatch (=). -Martin
Re: How to make a new operator.
On Fri, Mar 23, 2012 at 03:03:09PM +1300, Martin D Kealey wrote: On Thu, 22 Mar 2012, Carl Mäsak wrote: Jonathan Lang (), Daniel (): 1, 2, 4 ... 100 # same as 1,2,4,8,16,32,64 That last one doesn't work on Rakudo :-( And it never will. Note that 100 is not a power of 2, and that the goal needs to match exactly. Hmmm, so it's likely that most times you get a Num rather than an Int or Rat, those won't stop either? 1, 7 / 6.0 ... 2 1, sqrt(2), 2 ... 8 The expression 7/6.0 produces a Rat, so the first sequence properly stops at 2. On Rakudo on my system, sqrt(2) indeed produces a Num, but since floating point arithmetic doesn't result in sqrt(2) / 1 == 2 / sqrt(2), no geometric sequence is deduced and the sequence fails with unable to deduce sequence. Question: do we support 1, 2i, -4 ... 256 I think this ought to work, but for some reason Rakudo on my system hangs whenever I try it. The following does work in Rakudo: say 1, { $^x * 2i } ... 256 1 0+2i -4+0i -0-8i 16+-0i 0+32i -64+0i -0-128i 256+-0i The fact that the auto-deduced sequence hangs probably needs to be filed as a bug report for Rakudo. Pm
Re: How to make a new operator.
On 03/21/2012 09:07 PM, Daniel Carrera wrote: Hello, Is it possible to create a new range operator ':' such that: a:b is the same as a..b (this is the easy part) a:b:c is a range from 'a' to 'b' by steps of 'c'. For example, 2:15:3 == 2,5,8,11,14 That can be done by giving the new infix:: operator list associativity (niecza already supports this) :b is the same as 0..b create a new prefix operator... except that that prefix : is already taken for constructing pairs a: is the same as a..Inf create a postfix:: operator... except that postfix : is already taken as invocant marker ::c is the same as 0:Inf:c create a prefix::: operator. Except that this collides with existing syntax... : is the same as 0..Inf create a term::. There are hooks for all of that, but it requires you to come up with a new syntax that doesn't collide heads-on with lots of existing grammar rules. Cheers, Moritz
Re: How to make a new operator.
Hi Moritz a:b is the same as a..b (this is the easy part) a:b:c is a range from 'a' to 'b' by steps of 'c'. For example, 2:15:3 == 2,5,8,11,14 That can be done by giving the new infix:: operator list associativity (niecza already supports this) Can you explain or give me a link that explains how to do that? I can figure out a little bit on my own: multi sub infix::( Int $a, Int $b ) { # This is the case 'a:b' } multi sub infix::( Range $a, Int $b ) { # Is this correct? # I'm thinking that a:b:c could be interpreted as (a:b):c so it is Range : Int. # Am I on the right track? } :b is the same as 0..b create a new prefix operator... except that that prefix : is already taken for constructing pairs Ok. I hadn't realized that you could define the same symbol as prefix, infix and postfix... So.. ignoring the fact that : conflicts with existing syntax, I could do this: multi sub infix::( Int $a, Int $b ) { ... } multi sub infix::( Range $a, Int $b ) { ... } multi sub prefix::( Int $a ) { ... } multi sub postfix::( Int $b ) { ... } Right? : is the same as 0..Inf create a term::. Ok. There are hooks for all of that, but it requires you to come up with a new syntax that doesn't collide heads-on with lots of existing grammar rules. Thanks. I'll see if I think of something that feels natural but doesn't collide with anything. One option is to just use the existing .. operator: multi sub prefix:..( Int $b ) { 0..$b } multi sub postfix:..( Int $a ) { $a..Inf } Only problem is that something like 2..10..3 might be confusing. Hmm... I must have made a mistake here somewhere... After defining these functions, the traditional range '2..10' doesn't work anymore. I suppose that my new functions have a higher precedence than the traditional .. operator. I tried to fix this, but I failed: multi sub prefix:..( Int $b ) is looser(infix:cmp) { 0..$b } So, I'm not doing this right. Cheers. Daniel. -- I'm not overweight, I'm undertall.
Re: How to make a new operator.
Is it possible to create a new range operator ':' such that: Do you need to? a:b:c is a range from 'a' to 'b' by steps of 'c'. Perl 6 already has: $a,*+$c...* =$b E.g. 2, 5 ...^ *=15 2,5,8,11,14 :b is the same as 0..b Perl 6 already has ^$b e,g, ^100 0..99 a: is the same as a..Inf Perl 6 already has $a..* or $a...* e.g. 3..* 3,4,5,6, ::c is the same as 0:Inf:c Perl 6 already has: 0,$c...* e.g. 0,3...* 0, 3, 6, 9, 12 : is the same as 0..Inf Perl 6 already has: ^Inf 0,1,2,3,4,5, Damian
Re: How to make a new operator.
Daniel (), Damian (): : is the same as 0..Inf Perl 6 already has: ^Inf 0,1,2,3,4,5, Hah, Damian made an off-by-one error! Oh wait... // Carl
Re: How to make a new operator.
Damian (), Daniel (): Perl 6 already has: 0,$c...* e.g. 0,3...* 0, 3, 6, 9, 12 Interesting... but it doesn't seem to work in Rakudo Star (2012.02): @(2,5..10) 2 5 6 7 8 9 10 :-( Keep in mind that infix:.. will listify to the kind of one-step-at-a-time range that was produced above, whereas infix:... is its more DWIMmy cousin and would take the above as counting three steps at a time. It would also produce an infinite list, because by the rules you need the RHS of infix:... to match exactly, and 10 is not in the infinite list 2, 5, 8, 11, 14... Which is why you'd need to write something like * = 10. // Carl
Re: How to make a new operator.
Interesting... but it doesn't seem to work in Rakudo Star (2012.02): @(2,5..10) You need three dots, not two. Damian
Re: How to make a new operator.
On 21 March 2012 22:50, Carl Mäsak cma...@gmail.com wrote: It would also produce an infinite list, because by the rules you need the RHS of infix:... to match exactly, and 10 is not in the infinite list 2, 5, 8, 11, 14... Which is why you'd need to write something like * = 10. Ok, so infix:... isn't what I wish for either... Can you help me understand Damian's example? $a,*+$c...* =$b I see a lot of Perl magic here and I have no idea what any of it does. What does the first star do? And the plus sign? I tried to guess what the = does by experimentation, but I can't make heads or tails of it: 2..100 = 5 True 2...100 = 5 2 Also, I'm only now learning what ... does. I thought it was just the yada yada yada operator, but now I see that it makes an object called List(), which clearly is different from both Range() and Array()... Btw, I just found the section in S09 covering multi-dimensional arrays and the semicolon operator. I'll go read it now... One unrelated question: Is there a way to ask an object what methods it supports? That would make it easier for me to experiment. For example, just now I have been looking for the methods supported by the Range object (to see how I'd obtain the beginning and end points of a range) and haven't found anything. Cheers, Daniel. -- I'm not overweight, I'm undertall.
Re: How to make a new operator.
Ok, so infix:... isn't what I wish for either... Can you help me understand Damian's example? Breaking down that example: $a, # Start at $a *+$c # Generate next number via: sub($prev_num} { $prev_num + $c } ... # Repeat until... * =$b # ...this sub matches: sub($prev_num) { $prev_num = $b } * used as an argument to an operator is a shorthand for constructing subroutines, where the * represents the subroutine's argument. Damian
Re: How to make a new operator.
On 22 March 2012 00:08, Brandon Allbery allber...@gmail.com wrote: * + $c --- the next value is the current value plus $c. (* means Whatever, and generally refers to the current value of something. In this case, we're specifying how to make a new value given a current value. You can think of it as a way to make an anonymous function. In Haskell this would be (+ c) or \x - x + c; in Python, lambda x: x + c; in Perl 5, sub {$_[0] + $c}. The meaning of * is context dependent, though; when accessing array elements, for example, * refers to the end of the array, so @arr[* - 1] means the second last element of @arr.) Interesting... a lambda expression... my add3 = * + 3 WhateverCode.new() add3(2) 5 Cool... this actually works... But I notice that to use 'add3' in the list construction I need to put an ampersand: 2, add3 ... 14 2 5 8 11 14 Still... the fact that this works is neat. * = $b --- this determines where the sequence ends: when the current value is greater or equal to $b. So... after the ... you have an anonymous function that has to return 'True' for the sequence to end? Seems strange, but it works: # A function that always returns True = List of one item. 2,5...True 2 So if I want to go from $a to $b by steps of $c, the correct recipe would be: $a, *+$c ... * = $b - $c With this information, I can write something like this: sub infix:|( Range $r, Int $c ) { my ($a, $b) = $r.bounds; return $a, *+$c ... * = $b - $c } (2..10)|3 == 2, 5, 8 This would look better if I removed the parenthesis, but I'm having trouble telling Rakudo that this infix operator is looser than the .. operator: sub infix:|( Range $r, Int $c ) is looser( infix:.. ) { ... } No applicable candidates found to dispatch to for 'trait_mod:is'. haral:6704 Z$ ./perl6 -e 'say (2, 4 ... 10).^methods' Thanks. That's very useful. The .^ operator runs a method on the object's metaobject, which determines how it associates with its class and roles. The metaobject is available via the HOW method, but is not something you can print or etc.; working with it directly is somewhat painful, which is why .^ exists. Ok. -- I'm not overweight, I'm undertall.
Re: How to make a new operator.
On Wed, Mar 21, 2012 at 7:52 PM, Daniel Carrera dcarr...@gmail.com wrote: * = $b --- this determines where the sequence ends: when the current value is greater or equal to $b. So... after the ... you have an anonymous function that has to return 'True' for the sequence to end? Seems strange, but it works: # A function that always returns True = List of one item. 2,5...True 2 It actually smartmatches whatever is on the right hand side against the sequence, and stops when the smartmatch returns True. It just happens that you smartmatch an anonymous function, it executes the function and returns its result. In particular, note that True there is not an anonymous function, it's just the value True. You'd need to say { True } to get an anonymous function which returns True. Examples: 2, 5 ... 11 # smartmatch is true when you hit 11 2, 5 ... True # stop right away 2, 5 ... False # never stop 2, 5 ... * # shorter way of saying never stop 2, 1, 1/2 ... Num # stop when the number switches from a Rat to a Num 'a' ... /f/ # stop when the regular expression matches -- Solomon Foster: colo...@gmail.com HarmonyWare, Inc: http://www.harmonyware.com
Re: How to make a new operator.
On 22 March 2012 01:13, Solomon Foster colo...@gmail.com wrote: It actually smartmatches whatever is on the right hand side against the sequence, and stops when the smartmatch returns True. It just happens that you smartmatch an anonymous function, it executes the function and returns its result. I see... I still find this a little confusing. The idea of smart-matching a function just doesn't quite fit with my brain. I can memorize the fact that smart-matching 7 and foo means evaluating foo(7) and seeing if the value is true, but I can't say I understand it. Examples: 2, 5 ... 11 # smartmatch is true when you hit 11 2, 5 ... True # stop right away 2, 5 ... False # never stop 2, 5 ... * # shorter way of saying never stop 2, 1, 1/2 ... Num # stop when the number switches from a Rat to a Num 'a' ... /f/ # stop when the regular expression matches Interesting. Cheer, Daniel. -- I'm not overweight, I'm undertall.
Re: How to make a new operator.
My understanding is if you want to count by threes, starting at 2 and ending at 14, you should be able to write: 2, 5 ... 14 That is, the list-building operator looks at the previous two or three terms preceding it to determine where to start and what step function to use, and then looks at the first term following it to determine where to stop. The use of lambda functions in the immediately preceding and following terms provides a means to explicitly define the step function and the test condition, respectively; but Perl 6 is supposed to be smart enough to intuit linear step functions from two strictly numeric prior terms, geometric step functions from three such terms, and a test condition that stops the series at ' $n' from a numeric right term. So: 1, 3 ... 13 # same as 1,3,5,7,9,11,13 1 ... 10 # same as 1,2,3,4,5,6,7,8,9,10 1, 2, 4 ... 100 # same as 1,2,4,8,16,32,64 and 2, 5 ... 14 # same as 2,5,8,11,14 Meanwhile, using Whatever for the test condition means keep the series going indefinitely: 1, 3 ... * # every positive odd number. 1 ... * # all counting numbers. 1, 2, 4 ... * # all powers of 2. And using '...^' instead of '...' changes the default final test condition from ' $n' to '= $n': 1, 3 ...^ 13 # same as 1,3,5,7,9,11 1 ...^ 10 # same as 1,2,3,4,5,6,7,8,9 1, 2, 4 ...^ 100 # same as 1,2,4,8,16,32,64 In short, what Damian is talking about is the more powerful and reliable use of the syntax; but the above approach (assuming it has been properly implemented) is a more intuitive use that covers the most common cases. Make common things easy, and make uncommon things possible. Likewise, using Whatever in conjunction with operators is there to provide an intuitive way to calculate the next term from the previous one(s): 1, *+2 ... 13 # start at 1, step by 2s, stop at 13. 1, 1, *+* ... * # each new term is the sum of the previous two. 1, 1, infix:+ ... * # same as last one.
Re: How to make a new operator.
What I want to know is whether there's a way to define a step function that's based in part or in whole on the current term's index. For example, how would I use infix:... to generate the perfect squares between 0 and 100? Namely, '0,1,4,9,16,25,36,49,64,81,100'. For example, is Perl 6 set up to try to pass the current element's index into the step function by means of a named parameter? I would hope for something like: - :index { $index * $index } ... 100 or 1, *+:index ... * # 1,3,6,10,15,21,28,36,45,... (Note: I _don't_ expect the above to work as is; they're merely intended to convey a rough idea of what I _do_ want.) If not, how _would_ I generate these lists?