Re: Language Design: 'special casing' of split()? (i.e. .split performs concomitant .join? )
On Sun, 11 Oct 2020, Tobias Boege wrote: > On Sat, 10 Oct 2020, William Michels via perl6-users wrote: > > then proceed to process the function call. As it is my understanding that > > Raku incorporates a lot of different programming paradigms (imperative, > > object-oriented, functional, etc.), I'm not sure where this behavior falls > > on the 'paradigm ladder'. > > > > If you want to view it as a matter of paradigm, I guess it would be the > "operator-centric paradigm", except that it is a method and not an operator. > > The Array class inherits methods from Cool and when you call a method from > Cool on the Array, the Cool part of the array will answer the call. The > Array is Cool to advertise that it can be evaluated in numeric and string > "context". In string context, the array becomes joined using spaces as > delimiters. Put more bluntly: when you treat an array like a string > (by calling a string-related method of Cool on it), then Raku treats it > as a string, even if it must convert it to one before. [ This may sound > magical, but in reality Array just obtains the method .split from Cool > and its implementation explicitly converts the invocant, whatever it > may be, to a Stringy on which a sensible split is defined. ] > Oh, it seems like I was far too slow. From all the other answers, I think Brad put best what I tried to express using many redundant words. And he avoided the historically charged and probably inaccurate term "context". Best, Tobias
Re: Language Design: 'special casing' of split()? (i.e. .split performs concomitant .join? )
On Sat, 10 Oct 2020, William Michels via perl6-users wrote: > So I guess the first question I have is whether the 'auto-joining' of array > elements is specc'ed or not. > I did not find anything that explicitly requires @array.split() to force @array into a string, but there are tests in S02-types/list.t asserting that stringified lists must use a space as delimiter. > What you seem to be saying is that when calling a function on an array, the > first response is for Raku to call something similar to 'cat' on the array, No, definitely not. At least not "any function". Only functions (or methods or operators) by which you express the intent to treat the array as a string. > then proceed to process the function call. As it is my understanding that > Raku incorporates a lot of different programming paradigms (imperative, > object-oriented, functional, etc.), I'm not sure where this behavior falls > on the 'paradigm ladder'. > If you want to view it as a matter of paradigm, I guess it would be the "operator-centric paradigm", except that it is a method and not an operator. The Array class inherits methods from Cool and when you call a method from Cool on the Array, the Cool part of the array will answer the call. The Array is Cool to advertise that it can be evaluated in numeric and string "context". In string context, the array becomes joined using spaces as delimiters. Put more bluntly: when you treat an array like a string (by calling a string-related method of Cool on it), then Raku treats it as a string, even if it must convert it to one before. [ This may sound magical, but in reality Array just obtains the method .split from Cool and its implementation explicitly converts the invocant, whatever it may be, to a Stringy on which a sensible split is defined. ] The same principle makes code like `"2" ** 5` or `2.map: * ** 5` work, where in the first case a string 2 is treated as, and hence converted to, a number, and in the second case an integer is treated like a list and indeed Raku will arrange for that to happen on the fly. In those two cases it is exponentiation that forces the invocant to become a numberic and it is mapping that forces the invocant to become a listy thing transparently. In the same way splitting something forces it to become a string first. [ Again, it is not the language that somehow picks up *syntactical* clues from your code about what to convert to what, but it is the core implementation of, e.g., Any.map which is inherited by Int, in the above example, and converts whatever its invocant is to something that is iterable, because iteration is what you wanted to happen by calling .map on it. ] > I can point to the (functional) R-programming language to show what happens > there. When manipulating "array-like" (i.e. vector) objects in R, you can > do nested function calls, or sequential (piped) function calls, and still > get the same data structure out at the end. So a 10-element input gives a > 10-element output. In the R-GUI (i.e. REPL): > > > 0:9 > [1] 0 1 2 3 4 5 6 7 8 9 > > x <- 0:9 > > is.vector(x) > [1] TRUE > > length(x) > [1] 10 > > # using base-R: > > sqrt(tan(cos(sin(x > [1] 1.2479614276 0.8867679488 0.8398446968 1.2344525173 0.9431819962 > 0.8044843661 1.1966884594 > [8] 1.0064589934 0.7823305851 1.1415611482 Yes, so it seems that R prefers to vectorize function calls over arrays. In Raku, if you want to apply a method or sub or operator to every element of a list instead of the list object itself (which may have its own over- load or inherited version of that method causing it to behave strangely, which is the topic of this thread), you ought to use `map` or a hyper operator. In Raku, if you call sin on an array, that puts the array in a numeric context which makes the array collapse to the closest numeric thing that Raku makes the convention to associate with it: the number of its elements. Behold: my @x = 0..9; say @x.sin; #= -0.5440211108893698 = sin(10) This is an excellent example you chose, because .sin and .split both become methods of Array because Array inherits Cool. They both do not apply element-wise but cause the entire invocant array to adapt to context -- they become a number or a string depending on how you want to treat it. Best, Tobias -- "There's an old saying: Don't change anything... ever!" -- Mr. Monk
Re: Language Design: 'special casing' of split()? (i.e. .split performs concomitant .join? )
On Tue, 06 Oct 2020, William Michels via perl6-users wrote: > [...] > > So my question regards "special-casing" of split/join in Raku. Is the first > result on comma-delimited data the default, i.e. joining disparate elements > of an array together head-to-tail? Or is the second result on > whitespace-delimited data the default (i.e. no joining of disparate > elements together head-to-tail)? Which one is special-cased? If the second > one is special-cased, is that why Raku returns 5 elements and not 4 > elements as in lines C/D (implied join)? > My answer is going to be that there is *no* special-casing. You have an array of strings @a and you call the `split` and `join` methods on it. These two methods are not alike. `join` is a proper method of List and it joins stringifications of the elements of that list. Crucially, the `split` method comes from somewhere else: Array inherits it from the Cool class. When you call Array.split, what happens is that your entire array gets stringified first (joining stringifications of its elements with spaces) and then Cool.split is called on that string representation of your array. This is even mentioned in the introductory paragraph about Cool [1]. This is the strangely consistent explanation of the effects you observed. You see, the only "special" thing is that Array.split being a Cool method causes the array to be joined with *spaces* before the splitting starts, but this always happens, independently of the join/split arguments. Array.split does in particular *not* "pass on" the split call to the elements of the array. For that you would use @a».split, although this would cause (itemized) Seqs for each element of @a to end up in the returned list, so what you actually thought you were doing may be written as @a».&{ .split(",").Slip } I am sure there are ways to write it more alphabetically. Best, Tobias [1] https://docs.raku.org/type/Cool -- "There's an old saying: Don't change anything... ever!" -- Mr. Monk
Re: liens and :chomp question
On Sun, 30 Aug 2020, ToddAndMargo via perl6-users wrote: > >- You are calling .lines on the value of .IO.open which is an > > IO::Handle. IO::Handle.lines does not take a named argument > > :chomp, so passing one is useless. > > That explains it. > > Bu: > https://docs.raku.org/type/IO::Path#method_lines > > (IO::Path) method lines > Defined as: > > method lines(IO::Path:D: :$chomp = True, :$enc = 'utf8', :$nl-in = > ["\x0A", "\r\n"], |c --> Seq:D) > > Opens the invocant and returns its lines. > > The behavior is equivalent to opening the file specified > by the invocant, forwarding the :$chomp, :$enc, and > :$nl-in arguments to IO::Handle.open, then calling > IO::Handle.lines on that handle, forwarding any of > the remaining arguments to that method, and returning > the resultant Seq. > > The "signature" line (cryptogram) clearly stated that > ":$chomp" is a parameter of the method. > > Now you are obviously correct that :chomp is ignored. > If I am not mistaken, I have just tripped over another > error in the documentation. Your take? > You confuse two methods that have the same name "lines". One of them, which exists in the IO::Path class, has a :chomp argument. The other, on IO::Handle does not. "path".IO.lines() <-- calls lines on an IO::Path (supports :chomp) "path".IO.open.lines() <-- calls lines on an IO::Handle (does not support :chomp) In the second case, if you want chomping to happen you have to pass the :chomp to the *open* call, as you do below: > $ p6 'dd "Lines.txt".IO.open(:chomp).lines()[3,2];' > ("Line 3", "Line 2") > > $ p6 'dd "Lines.txt".IO.open(:!chomp).lines()[3,2];' > ("Line 3\n", "Line 2\n") > > $ p6 'say "Lines.txt".IO.open(:!chomp).lines()[3,2];' > (Line 3 > Line 2<-- why the space? > ) > The better question is "whose space". You print again the List of lines you obtain by indexing the return value of .lines, so expect output in the form of "(item1 item2 ...)". This is where your space comes from. Lists print that way. They insert spaces between their elements. In this case, you had :chomp disabled, so the "Line 3" item printed "Line 3\n", including the newline that was not chomped, then the space and then the next item, "Line2\n" with its newline, then the closing parenthesis which is also part of printing a List. This serves to better illustrate where one element of the List ends and where the next begins. The space separate them: $ rakudo -e 'say "Lines.txt".IO.open(:!chomp).lines()[3,2].map({ "«$_»" });' («Line 3 » «Line 2 ») Best, Tobias -- "There's an old saying: Don't change anything... ever!" -- Mr. Monk
Re: liens and :chomp question
On Sat, 29 Aug 2020, ToddAndMargo via perl6-users wrote: > Hi All, > > I am trying to figure out how to use line with :$chomp. > Now what am I doing wrong? > > > $ alias p6 > alias p6='perl6 -e' > > $ p6 'say "Lines.txt".IO.open.lines(:chomp)[3,2];' > (Line 3 Line 2) > > $ p6 'say "Lines.txt".IO.open.lines(:!chomp)[3,2];' > (Line 3 Line 2) > > I am looking for > > Line 3 > Line 2 > Then I would suggest say $_ for "Lines.txt".IO.lines[3,2] > Now what am I doing wrong? - You are calling .lines on the value of .IO.open which is an IO::Handle. IO::Handle.lines does not take a named argument :chomp, so passing one is useless. The .lines method on an IO::Path, however, which I call in my snippet, supports such an argument. You could call .IO.lines(:chomp) or .IO.open(:chomp).lines. - You should use :chomp and not :!chomp because :chomp removes the trailing newline from every line read for you. When you use `say`, a trailing newline is added automatically, so in order to get only one newline in the output per item, you have to :chomp. The :chomp argument does not appear in my snippet because it is the default, but you could have done say $_ for "Lines.txt".IO.lines(:!chomp)[3,2] to see the effect of not chomping. - What you `say` is the return value of indexing the Seq that is returned by .lines. This is an object of type List and will always print in the format "(item1 item2 ...)" and not in the format you desire. In the snippet above I iterate over that List with `for` and print every item in a new line. Best, Tobias -- "There's an old saying: Don't change anything... ever!" -- Mr. Monk
Re: lines :$nl-in question
On Fri, 28 Aug 2020, ToddAndMargo via perl6-users wrote: >https://docs.raku.org/type/IO::Path#method_lines > >(IO::Path) method lines > >Defined as: > >method lines(IO::Path:D: :$chomp = True, :$enc = 'utf8', :$nl-in = > ["\x0A", "\r\n"], |c --> Seq:D) > >Opens the invocant and returns its lines. > >The behavior is equivalent to opening the file specified >by the invocant, forwarding the :$chomp, :$enc, >and :$nl-in arguments to IO::Handle.open, then calling >IO::Handle.lines on that handle, forwarding any of the >remaining arguments to that method, and returning the >resultant Seq. > > And if I am not pushing it, what is `|c`? > > [...] > I do not understand The description of this method says that it shall do two things: - open the invocant path (IIRC you like to use the phrase "what is fed into it" instead of "invocant") which returns an IO::Handle, - then call the lines method on this IO::Handle, resulting in a sequence of lines (Seq in Raku), and it should return this same Seq value. The lines method on an IO::Path does the same as the lines method on an IO::Handle, except that it has to open the path before to get a handle. The arguments to the IO::Path.lines method therefore split into two groups: - :$chomp, :$enc, :$nl-in which are passed on to the open call in the first bullet point above, - all the remaining arguments, whatever they are, are *captured* by the syntax |c and will be forwarded to the IO::Handle.lines call in the second bullet point above. The |c is a so-called capture parameter [1]. It is used in a signature (what you stubbornly call "cryptogram") when a method wants to inspect some (or none) of the arguments it got but keep all the others in a black box, named c here. The capture black box allows forwarding these extra arguments to some other call. The point is that the IO::Path.lines method does not need to know which arguments the target IO::Handle.lines method accepts. It only needs to take everything in and pass it on. It follows that you read about the meaning of the individual arguments or which arguments it makes sense to pass to IO::Path.lines in the documentation pages for the IO::Handle.open and IO::Handle.lines methods, which are linked to in the text. Really, everything that IO::Path.lines does is redistribute its arguments to two other method calls. The documentation of lines does not tell you that |c is a capture parameter, but it described what it is used for with the slide-in [...] forwarding any of the remaining arguments to that method [...] in the paragraph you quoted. The connection of that slide-in with the "|c thing" is a matter of text comprehension. Best, Tobias [1] https://docs.raku.org/type/Signature#Capture_parameters -- "There's an old saying: Don't change anything... ever!" -- Mr. Monk
Re: Raku User's Survey 2020 out now....
On Thu, 27 Aug 2020, ToddAndMargo via perl6-users wrote: > To pick out particular lines: >$ cat Lines.txt | raku -e '.say for lines()[3,2,5]' >Line 3 >Line 2 >Line 5 > > If it is, it is buried somewhere. > > And what goes inside the ()? That may seem like a dumb > remark (especially since I live and die in Top Down and > know very well what the () does) but it is a common mistake > I make with lines is forgetting the () when using the []. > How does that mistake manifest? I cannot see a way in which omitting the sub call parentheses in code like that could possibly lead to some different behavior. -- "There's an old saying: Don't change anything... ever!" -- Mr. Monk
Re: Seq whitespace sensitivity? (was Re: print particular lines question)
On Wed, 26 Aug 2020, Tobias Boege wrote: > Observe: > > > 1 ...^ 20 > (1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19) > > > 1 ... ^20 # actually C«1 ... (0..19)» > (1 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19) > > The documentation [1] states that the C«...» infix is list-associative > and while I have never seen an example of that (including in that docs > page), it would explain why it happily takes in your list (1) and then > your list (0 .. 19) and concatenates them into a sequence, without > applying any of the usual sequence operator magic. And I must correct myself. The associativity has nothing to do with this. I don't know where my mind was when I wrote that. From the documtation, I would blame the slurpy argument **@ for that behavior of just taking in lists and effectively iterating them into a new Seq, and in Rakudo it is apparently this special candidate: # https://github.com/rakudo/rakudo/blob/e2855aa/src/core.c/operators.pm6#L129 multi sub infix:<...>(\a, Mu \b) { Seq.new(SEQUENCE(a, b)) } Best, Tobias
Re: Seq whitespace sensitivity? (was Re: print particular lines question)
On Wed, 26 Aug 2020, William Michels via perl6-users wrote: > > They can be pretty great, especially when combined with the magic op= > > operators that (in essence) know about identity elements. I've done a few > > challenges on the Code Golf Stackexchange site where I wanted an infinite > > sequence like this: > > > > 0, 1, -2, 3, -4, 5, -6, ... > > > > It took me a while to realize this can be expressed in Raku simply as: > > > > { $++ * ($ *= -1) } ... * > > > > Hi Sean, that's a neat solution! I seem to have found an oddity though > (whitespace sensitivity). In the REPL: > > > say { $++ * ($ *= -1) } ...21 > (0 1 -2 3 -4 5 -6 7 -8 9 -10 11 -12 13 -14 15 -16 17 -18 19 -20 21) > > say { $++ * ($ *= -1) } ...^21 > (0 1 -2 3 -4 5 -6 7 -8 9 -10 11 -12 13 -14 15 -16 17 -18 19 -20) > > say { $++ * ($ *= -1) } ... 21 > (0 1 -2 3 -4 5 -6 7 -8 9 -10 11 -12 13 -14 15 -16 17 -18 19 -20 21) > > say { $++ * ($ *= -1) } ... ^21 > (0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20) > > I would have expected the last line of code (whitespace between "..." > and "^21") to give the same answer as the first three. Any ideas? > The difference is likely to come from the fact that "^20" as a term is a shorthand for the range "0..^20", while "...^" is the sequence operator with exclusive endpoint. Placement of whitespace will dictate where the little hat attaches to and thus change the meaning of the statement. Observe: > 1 ...^ 20 (1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19) > 1 ... ^20 # actually C«1 ... (0..19)» (1 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19) The documentation [1] states that the C«...» infix is list-associative and while I have never seen an example of that (including in that docs page), it would explain why it happily takes in your list (1) and then your list (0 .. 19) and concatenates them into a sequence, without applying any of the usual sequence operator magic. When you write "1 ...^20" I suppose that longest-token matching prefers the former interpretation as it makes the infix token longer. Best, Tobias [1] https://docs.raku.org/language/operators#index-entry-..._operators -- "There's an old saying: Don't change anything... ever!" -- Mr. Monk
Re: Combining multiple "is..." traits into one?
On Wed, 12 Aug 2020, Stuart Hungerford wrote: > Hi, > > I'm working with roles where the mixing-in classes and roles need to > have some mixin-specific notion of equality. So I have an Equality > role that can also be > mixed in as needed: > > role Equality { > method equal(Equality:D) of Bool:D {...} > } > > To make using the role easier I've created an infix operator "=/=". To > give the infix operator predcitable semantics I need to specify the > precedence and the associativity with traits: > > sub infix:<=/=>(Equality:D \x, Equality:D \y) of Bool:D is > equiv(&infix:<==>) is assoc is export { > x.equal(y) > } > > Is there some way to combine traits to a more succinct trait? Something like: > > subset Equivalence of Routine where {magic}...; > > sub infix:<=/=>(Equality:D \x, Equality:D \y) of Bool:D is equivalence > is export; > > Would a custom version of the trait_mod: routine do the trick? Yes: multi trait_mod: (Routine $r, :$equivalence!) { trait_mod:($r, :equiv(&infix:<==>)); trait_mod:($r, :assoc); } At the same time you can mix in a role if you need to, by adding `$r does Equivalence`. If you want to query this information of a predefined operator to make a subset, check for instance dd &infix:<+>.prec # Hash element = {:assoc("left"), :prec("t=")} at least on Rakudo. I have no idea if this attribute or the format for the 'prec' key in particular are standardized. Best, Tobias
Re: subs and the type system
On Mon, 20 Jul 2020, Gianni Ceccarelli wrote: > Aside: > > ``(sub (Int $ --> Int) {}) ~~ Walkable`` is false, because > ``:(Int $ --> Int) ~~ :(Numeric $ --> Numeric)`` is false, which is > correct because function subtypes should be contravariant in the parameter > types and covariant in the return type (i.e. if the caller passes a > Numeric, the callback should accept a Numeric or a *more general* > type, and if the caller expects a Numeric back, the callback should > return a Numeric or a *more specific* type). > > But then ``:(Numeric $ --> Int) ~~ :(Numeric $ --> Numeric)`` is also > false, and I feel like it should be true. Opinions? > My _opinion_ is that you are right, be it only because there exist words reminiscent of category theory that describe your desired behavior :-) But the source code of a Signature smartmatching another Signature [1] explicitly uses smartmatching for the parameter types and uses the unforgiving container identity operator to compare the return types: 91 return False unless self.returns =:= $topic.returns; The `eqv` implementation for two Signatures uses `=:=` as well, so this restriction seems deliberate. Changing the `=:=` to a `.does` call makes your code snippet work: $ ./rakudo-m -e 'say :(Numeric $ --> Int) ~~ :(Numeric $ --> Numeric)' True but it creates problems with roast that appear to spread multiple parts of the language. Failing tests are: t/spec/S10-packages/precompilation.rakudo.moar (Wstat: 65280 Tests: 32 Failed: 0) t/spec/S02-types/compact.rakudo.moar(Wstat: 256 Tests: 0 Failed: 0) t/spec/S02-types/native.rakudo.moar (Wstat: 256 Tests: 0 Failed: 0) t/spec/S06-currying/positional.t(Wstat: 256 Tests: 0 Failed: 0) t/spec/S06-signature/closure-parameters.rakudo.moar (Wstat: 256 Tests: 21 Failed: 1) t/spec/S09-typed-arrays/native-int.rakudo.moar (Wstat: 65280 Tests: 169 Failed: 0) t/spec/S09-typed-arrays/native-num.rakudo.moar (Wstat: 65280 Tests: 157 Failed: 0) t/spec/S09-typed-arrays/native.t(Wstat: 65280 Tests: 3 Failed: 0) t/spec/S17-lowlevel/cas-int.t (Wstat: 256 Tests: 0 Failed: 0) t/spec/S17-promise/nonblocking-await.t (Wstat: 256 Tests: 0 Failed: 0) t/spec/S32-array/splice.rakudo.moar (Wstat: 256 Tests: 0 Failed: 0) t/spec/S32-basics/xxPOS-native.t(Wstat: 65280 Tests: 15 Failed: 0) t/spec/S32-list/iterator.t (Wstat: 65280 Tests: 48 Failed: 0) t/spec/integration/precompiled.t(Wstat: 256 Tests: 9 Failed: 1) Some failures are very dubious like this error, resulting in the test not even starting (there are multiple of this sort, as you can see): $ ./rakudo-m -Ilib t/spec/S06-currying/positional.t ===SORRY!=== No appropriate parametric role variant available for 'array::intarray' Maybe my small changes (patch attached) create inconsistencies with these other parts of the language (oftentimes related to native types?), or maybe the test suite relies on (hence specifies) non-covariance. I don't know. Best, Tobias [1] https://github.com/rakudo/rakudo/blob/master/src/core.c/Signature.pm6#L34-L93 PS: I want to note that my first attempt naïvely replaced the `=:=` with `~~` but this set roast even more on fire which I think is related to `~~` autothreading on junctions, as opposed to `=:=` and `.does`. -- "There's an old saying: Don't change anything... ever!" -- Mr. Monk diff --git a/src/core.c/Signature.pm6 b/src/core.c/Signature.pm6 index ea2b5cabe..72eff7bdd 100644 --- a/src/core.c/Signature.pm6 +++ b/src/core.c/Signature.pm6 @@ -88,7 +88,7 @@ my class Signature { # declared in BOOTSTRAP return False unless $hasslurpy; } } -return False unless self.returns =:= $topic.returns; +return False unless $topic.returns.does(self.returns); True; } @@ -160,7 +160,7 @@ multi sub infix:(Signature:D \a, Signature:D \b) { return False unless a.WHAT =:= b.WHAT; # different return -return False unless a.returns =:= b.returns; +return False unless a.returns.does(b.returns); # arity or count mismatch return False if a.arity != b.arity || a.count != b.count;
Re: subs and the type system
On Mon, 20 Jul 2020, Theo van den Heuvel wrote: > Hi gurus, > > after looking at the documentation on Sub, Signature and the raku type > system I find myself unable to constrain the types of functions in the way I > think I need. > > The situation: I have a function, let's call in 'walker', whose first > parameter is a callback. > I wish to express that only callbacks with a certain Signature and return > type are acceptable. > Let's say the callback should follow :(Numeric $n --> Numeric). My callback > is going to be more complicated, but for simplicity sake. > > I was hoping to be able to use a named type of function with this signature. > I know I can say > > my $sig = :(Numeric $n --> Numeric); > > but my attempts to use $sig fail. I found no example of an application > beyond smartmatching. > > [...] > > but I was hoping for an explicit type, maybe using class, or subset or > roles. > I hope to say soemething like > > sub walker(Walkable &callback, ...) > > What am I missing here? > You said that you know how to check signatures via smartmatching. Smartmatching is great, there isn't much to know beyond it. The way to shoehorn smartmatching into the type system is `subset`: subset Walkable of Callable where { .signature ~~ :(Numeric --> Numeric) }; If your callback signature is more complicated, all the more reason to give it a name via subset. You can use it now almost like you wanted: sub walker (Walkable $w) { say $w($_) for 1..10 } walker(-> Numeric $x --> Numeric { $x.sqrt }); # WORKS walker(-> $x { $x.sqrt }); # DOESN'T You cannot write `Walkable &w` in the signature of &walker because the combination of a type and the &-sigil apparently means that `&w` should be Callable and return a Walkable. That's why I use the $-sigil. [*] Note that if you constrain the signature of a Callable, then you have to provide the appropriate signature statically, as demonstrated. Best, Tobias [*] N.B. I failed to find a reference for this in the documentation. I discovered it by writing `sub walker (Int &w)` and provoking a type checking error which told me that it was expecting `Callable[Int]`. (That was also my gut feeling.) According to source code, Callable is a parametric role in Rakudo whose first parameter indeed is the return type. This is all somewhat nebulous to me (how does the Callable- parametric way to specify return type compare with smartmatching against .signature, for example? They don't seem equivalent!), so I stick with the $-sigil. -- "There's an old saying: Don't change anything... ever!" -- Mr. Monk
Re: root cubic
On Thu, 09 Jul 2020, Tobias Boege wrote: > Now, there are effective ways to represent algebraic numbers like 9 ** (1/3) > in such a way that you can do arithmetic with them, but I'm not aware of any > implementation of that available to Raku. For someone with enough tuits, > I think this [1] can serve as a sort of high-level manual for creating such > a module. In terms of ready-made non-Raku packages, I only know of CGAL [2], > which provides a clean and even (template-)parametric interface to real > algebraic numbers. In fact, I might have a try at NativeCall'ing it this > evening. > Here is a super spartan version of this: https://github.com/taboege/raku-Real-Algebraic The module is: - not the most straightforward to build (but given all dependencies, zef should do everything required automatically, and it should warn about missing dependencies), - not well integrated with the rest of Raku, - untested. But it accomplishes the following: my \η = - (8ra).kth-root(4); Turn the literal 8 into a Real::Algebraic number so that methods and operator overloads work, then take its real, positive 4th root and negate that number for good measure. η is now an instance of Real::Algebraic. say η ** -4 == (1/8)ra; # OUTPUT: «True» As expected, raising it to the -4th power produces another Real::Algebraic number (in some hidden internal representation) that can be successfully compared for equality against 1/8. Note that the Num version of this, `8.sqrt.sqrt ** -4 == 1/8`, yields False, just like `0.1 + 0.2 == 0.3` is false in languages that don't use rationals for decimal literals. And finally, there is a FatRat coercer that gives you arbitrarily close rational approximations, here accurate to within at least 200 decimals (compare with WolframAlpha, for instance): say η.FatRat(1e-200).nude; (-2319046107914249546164017690226327191927995914167183915057429614886355365218221502899659586060964349175885087790712999436533151194306883153880674634813417790513862919501362233566580543228616216472448597249046963887795 1378913065775496824682182051857728448902028277271278088224317349054049721856053955032165000485952146958446223387833982704161766047792183079895777875237766653530662154044294980748355504146827894396365898183024673030144) But this is as far as my interest in this goes at the moment. Hope it is interesting to some. Best, Tobias -- "There's an old saying: Don't change anything... ever!" -- Mr. Monk
Re: root cubic
On Thu, 09 Jul 2020, Aureliano Guedes wrote: > Hi all, > > A quick question. > > This is expected? > > raku -e 'say 9 ** (1/3)' > 2.080083823051904 > > > Why do I'm asking this? > I know about the computational floating problem and I also know that the > Raku deal with rational whenever it is possible and store numbers as > expressions (actually I don't know if there are more details). That's why > 0.2 + 0.1 == 0.3 in Raku returns True whilst in other languages like > Python, Perl5, and Ruby return False. > > Then, I was just playing around and I'd like to check if it is expected. > I for one expected it. The equation 0.1 + 0.2 == 0.3 uses the Rat type in Raku, which stores rational numbers as exact fractions of numerator and denominator, avoiding the floating point inaccuracies you mention, and hence making equality comparisons trustworthy. The number 9 ** (1/3) is not rational and in general exponentiation with a fractional power might not produce a rational number, so exact representation via Rat is out of the question. Therefore Rakudo does the computation with Num, which are inexact floating point values again. Now, there are effective ways to represent algebraic numbers like 9 ** (1/3) in such a way that you can do arithmetic with them, but I'm not aware of any implementation of that available to Raku. For someone with enough tuits, I think this [1] can serve as a sort of high-level manual for creating such a module. In terms of ready-made non-Raku packages, I only know of CGAL [2], which provides a clean and even (template-)parametric interface to real algebraic numbers. In fact, I might have a try at NativeCall'ing it this evening. Best, Tobias [1] https://math.stackexchange.com/a/3144516 [2] https://www.cgal.org/ -- "There's an old saying: Don't change anything... ever!" -- Mr. Monk
Re: why so different
On Mon, 22 Jun 2020, Aureliano Guedes wrote: > Thank you for the clarification. > > There is a method to set Rat precision at the scope of the program to apply > to all *.Rat() cases? > I don't know, based on a quick search in the documentation, of any global setting. The hacky solution would be to wrap the method like this: say pi.Rat.nude; # OUTPUT: (355 113) Num.^find_method('Rat').wrap: -> |c { # Make the default argument 1e-20 callwith |(|c, 1e-20 if c.elems ≤ 1) }; say pi.Rat.nude; # OUTPUT: (245850922 78256779) This program has three parts. First, we print pi.Rat.nude for comparison. The nude method returns numerator and denominator of a Rat as a list. The last part is just looking at pi.Rat.nude again to confirm that the change in the middle has worked and increased the default precision. You said you are relatively new to Raku, so let me explain the middle part. Raku has a special syntax for calling metamethods (i.e. doing introspection) on an object or type, which is the .^ operator. I use it to access an object representation of the Rat method on the Num type. I can wrap some code of my liking around this method via its wrap method. The `-> |c { … }` syntax creates an anonymous code block that wraps around the Num.Rat method and it accepts all arguments that may be passed as a Capture [1] in the variable c. If that Capture does not have a first parameter, i.e. the precision is not specified, I sneak in my 1e-20. Afterwards, the `callwith |(…)` part unpacks the (modified) captured arguments and calls the original method that I am wrapping [2]. Effectively, I pass a precision of 1e-20 whenever the caller did not pass a precision. You can see that the wrapping takes effect immediately in the last line of the above program. Ideally, this could be turned into a module that hides the questionable means behind a dynamic $*RAT-PRECISION variable or so. That is, unless someone comes up with an even better solution. Best, Tobias [1] https://docs.raku.org/type/Capture [2] https://docs.raku.org/routine/wrap -- "There's an old saying: Don't change anything... ever!" -- Mr. Monk
Re: why so different
On Mon, 22 Jun 2020, Aureliano Guedes wrote: > Hi all, > > First, I'm naive in Raku. Then let's go to my question. > > I'm trying to figure out why we got so different results here: > > > e.Rat()**(pi.Rat()*i) > -0.9902-1.3942922582021257e-07i > > e**(pi*i) > -1+1.2246467991473532e-16i > > e.Rat()**(pi.Rat()*i) == e**(pi*i) > False > > I understand the Num actually have the traditional behavior which leads > this: > 0.1.Num() + 0.2.Num() != 0.3.Num() > > And Rat is awesome cos deal nice to the real world. > > Anyway, I do not expect so different results between Rat and Num. > First, e and π are not rational numbers, so Num (IEEE 754 double) and Rat (pair of bigint numerator and denominator) both will be only approximations. The literals e and pi in Raku are typed as Num and when you call the Rat method on them, you get a Rat back with the *default* precision of 1e-6 [1]. That is a lot less precise than the Nums you started with, hence the difference. Try supplying a large enough precision: > e.Rat(1e-200)**(pi.Rat(1e-200)*i) -1+1.2246467991473532e-16i This is better than a default .Rat() but notice that you cannot get past the limited precision in the source Nums, which is ca. 1e-16. Best, Tobias [1] https://docs.raku.org/routine/Rat -- "There's an old saying: Don't change anything... ever!" -- Mr. Monk
Re: junctions and parenthesis
On Mon, 22 Jun 2020, Elizabeth Mattijsen wrote: > BEGIN trait_mod:(&any, :tighter(&infix:<*>)); > > comes to mind, but that doesn't seem to do the trick. > My guess: tighter and looser are only consulted by the parser in contexts where 'any' was recognized as an *operator*.
Re: junctions and parenthesis
On Mon, 22 Jun 2020, Joseph Brenner wrote: > Patrick R. Michaud wrote: > > > The "any" function is just like any other function taking an arbitrary list > > of arguments (including user-defined functions). As such it parses with > > lower precedence than comparison operators -- so "eq" binds more tightly > > than "any". > > Thanks, makes sense. > > > I'm not exactly sure what sort of warning should go here, or how it'd be > > detected. > > Yes, exactly. From one point of view it's working as designed-- to me > it felt pretty weird, though. > > Speculating wildly: could there be a need for a different type of > function with different precedence? > You can achieve this today by redefining &any to be a prefix operator and provide it with tight enough precedence. In this example, I pick infix multiplication as the argument stopper, which is in particular tighter than the relevant eq operator; your mileage may vary: sub old-any (|c) { CORE::{'&any'}.(|c) } multi prefix: (|c) is tighter(&infix:<*>) { old-any |c } say so any eq any ;# True (fixed) say so old-any() eq old-any(); # True say so old-any eq old-any ; # False Now I'd be interested to see how someone would turn this into a frugal-sub declarator or an `is frugal` trait. Regards, Tobias -- "There's an old saying: Don't change anything... ever!" -- Mr. Monk
Re: I need help sorting a list
On Sun, 24 May 2020, Elizabeth Mattijsen wrote: > Hmmm... it appears we need to numerify the match to get numeric comparison > semantics, so we put a "+" before the match: > > $ raku -e 'my @x=.sort: { +m/ \d+ $/ }; for @x { say $_; > }' > a1 > a2 > a5 > a123 > a133 > So I think this would be a more general "version sort" then, where the number doesn't have to be at the end only: @things.sort: { .comb(/ \d+ | \D+ /) .map({ .Int // .self }) } It does not conform to all the rules about natural sort on Rosetta Code [1] but I like how - longest-token matching, - .sort behavior on (differently-sized) tuples, and - .Int returning an (undefined) Failure work together here. Regards, Tobias [1] https://rosettacode.org/wiki/Natural_sorting -- "There's an old saying: Don't change anything... ever!" -- Mr. Monk
Re: I need help sorting a list
On Sun, 24 May 2020, ToddAndMargo via perl6-users wrote: > On 2020-05-24 02:24, Elizabeth Mattijsen wrote: > > dd .sort: { m/ \d+ $/ } > > > > Hi Elizabeth, > > This seems to work: > >$ raku -e 'dd .sort: { m/ \d+ $/ };' >("a5", "a6", "a33", "a111").Seq > > > But I can't figure out how to get it into an array: > >$ raku -e 'my @x=.sort: { m/ \d+ $/ }; for @x { say > $_; }' >a5 >a2 >a123 >a133 >a1 > I think getting it into an array is not the problem, you did the right thing by assigning the Seq into @x. The sort characteristic that Liz used, { m/ \d+ $/ }, doesn't do the right thing (at least for me). I cannot tell you why it is an apparent no-op, though. Converting the extracted Match to an Int does work: $ raku -e 'my @x = .sort: { +m/ \d+ $/ }; dd @x' Array @x = ["a1", "a2", "a5", "a22", "a123", "a133"] Regards, Tobias -- "There's an old saying: Don't change anything... ever!" -- Mr. Monk
Re: sqrt and Buf question
On Thu, 14 May 2020, ToddAndMargo via perl6-users wrote: > Hi All, > > 1) how do I get 40 or more digits out of sqrt? > Meaningful digits? Not possible as sqrt uses limited precision. I think the IEEE 754 doubles that I would suspect to be used internally are capped way below 40 significant decimal digits. > 2) how to I assist those bytes to a 40 (or more) > byte long Buf? > > This obviously does not work: > > my Num $x = 3.sqrt; my Buf $y = Buf.new($x) > > Type check failed in initializing element #0 to Buf; expected uint8 but got > Num (1.7320508075688772e0) > in block at line 1 > You can convert the Num to a string and put that string into a Buf: Buf.new(3.sqrt.Str.encode) That's what I'd do without any clue at all about who is supposed to use this Buf. At least the buffer is about as long as the number is decimal digits, which seems to be what you wanted? Regards, Tobias
Re: NativeCall questions
On Fri, 08 May 2020, David Santiago wrote: > I also noticed that although my data string is defined as > CArray[uint8], when i loop through the array, the values are signed > ints: > > say $_ for $ed.data[0..10]; > > output: > > -98 There is an old open bug report about this: https://github.com/Raku/old-issue-tracker/issues/5859 Best, Tobias
Re: subst :g and captures in the replacement
On Sun, 19 Apr 2020, yary wrote: > How would one do s/(.+),(.+)/$1,$0/ using .subst ? > -y You can pass a code block as the second argument which assembles the replacement text. The block is evaluated anew for every substitution and it has access to the latest captures: say .subst(/(.*) ',' (.*)/, { "$1,$0" }) for «a,z 10,12 l,25» # z,a # 12,10 # 25,l Regards, Tobias -- "There's an old saying: Don't change anything... ever!" -- Mr. Monk
Re: subst :g and captures in the replacement
On Sun, 19 Apr 2020, yary wrote: > Question from today's Raku meetup. This works in a way I expect > > > 'fosdffgg'.subst(/f+/,"( "~ * ~" )", :g); > ( f )osd( ff )gg > > This one, $0 gets the single f each time > > > 'fosdffgg'.subst(/(f+)/,"( $0 )", :g); > ( f )osd( f )gg > > Bug or misunderstanding on my part? > Not a bug. You are calling the subst method on a string. Naturally, in order to perform the call, all the arguments you pass have to be evaluated first. This includes interpolating $0 into the string "( $0 )". You take whatever $0 contains, put it into a string and pass that into subst. In your case $0 seemed to confusingly stringify to "f". Consider this instead: "oops" ~~ /^(..)/ andthen say 'fosdffgg'.subst(/(f+)/,"( $0 )", :g) # OUTPUT: «( oo )osd( oo )gg» where I deliberately set $0 beforehand. Your first variant works because you pass a Callable into subst and when you do that subst will repeatedly evaluate the Callable. Not so when you pass a string value. Regards, Tobias -- "There's an old saying: Don't change anything... ever!" -- Mr. Monk
Re: tip: Windows, Git, and those nice Linux utilities
On Thu, 09 Apr 2020, ToddAndMargo via perl6-users wrote: > On 2020-04-09 09:39, Richard Hainsworth wrote: > > Am I missing something here? > > > > It would seem obvious to me that Git and Raku are not linked in any way, > > except of course for developers who only use Git with Raku, or who only > > have a dependency on Git through zef. > > > > It would therefore seem to me that a Raku / Zef distribution should NOT > > bundle Git. Consequently, 'Git' is not "forgotten" and that is *should* > > be installed independently. > > Git is required for Zef to operate. So Git is a dependency > of Zef. Therefor Zef should either include Git or warn > the user that he needs to download it himself That's an exaggeration. git is a dependency of the p6c ecosystem that zef is preconfigured to support. But zef currently supports CPAN as well which does not need git. If you don't have git installed, you get access to CPAN (and of course modules you install from your own local filesystem) but not p6c. Whether that is enough is your call. AFAICS, git is not a dependency of the zef packge in Fedora either. I just started a fresh VM, installed Rakudo and zef and then via zef a module and its dependencies -- all without git. Regards, Tobias -- "There's an old saying: Don't change anything... ever!" -- Mr. Monk
Re: regex objects as hash keys
On Sun, 05 Apr 2020, Joseph Brenner wrote: > I find in Raku that (as expected) I can use an object as a hash key: > > class Rutabaga { method color { say "purple (and white)"; } } > > my $obj = Rutabaga.new > my %vegeout; > %vegeout{ $obj } = "this works"; > > And for something I was doing I wanted to save up > data about matches for various different regexs, > so I thought I could just use a hash for this, like so: > > my (%match_locs, $loc); > > my $godzilla_rx = rx:i{ << godzilla >> }; > if $text ~~ m/$godzilla_rx/ { > $loc = $/.from; > say "Godzilla: Found at $loc!"; > %match_locs{ $godzilla_rx } = $loc; > } > > But using a regex object as a hash key evidently doesn't work, > it gives you the warning message: > ># Regex object coerced to string (please use .gist or .perl to do that) > > And what's worse is it coerces to an *empty list* which means *every* > regex is treated as the same key. > > If you I follow the advice to use the *.perl, then that works, of course: > > %match_locs{ $godzilla_rx.perl } = $loc; > > But you wouldn't be able to use the keys of the hash as a regex > object later, which seems sub-optimal, though not a concern for > my present purposes. The same thing happened with your Rutabaga object. It had a default Str method that was called when you used it as a hash key. It didn't really store the object in the key but just its .Str: %vegeout.keys.any ~~ Rutabaga; # OUTPUT: «False» %vegeout.keys.all ~~ Str; # OUTPUT: «True» %vegeout.keys[0] === $obj; # OUTPUT: «False» This is because Hash objects, by default, have Str(Any) keys, meaning Str and coercing when required. If you want a Hash which allows any kind of object as key, you have to declare it such: my $obj = Rutabaga.new; my %vegeout{Any}; # <-- see: https://docs.raku.org/language/hashmap#Non-string_keys_(object_hash) %vegeout{$obj} = "this works"; %vegeout.keys.all ~~ Rutabaga; # OUTPUT: «True» %vegeout.keys[0] === $obj; # OUTPUT: «True» This will also work with Regex objects. Regards, Tobias -- "There's an old saying: Don't change anything... ever!" -- Mr. Monk
Re: What is operand 152 and 160?
On Tue, 31 Mar 2020, ToddAndMargo via perl6-users wrote: > Hi All, > > Windows 10-1909 Pro > > raku -v > This is Rakudo version 2020.01 built on MoarVM version > 2020.01.1 implementing Perl 6.d. > > Running my program I get this at a call to > a sub in a module: > > operand type 160 does not match register type > 152 for op decont_u in frame WinCreateKey > > What is operand 152 and 160? > A cursory look around the MoarVM and nqp sources leads me to believe that they're bitmasks describing conditions of operands somewhere in the bytecode. 152 would be uint32 and 160 an uint64, without any extra flags set for them. -- "There's an old saying: Don't change anything... ever!" -- Mr. Monk
Re: irrational nubmer?
On Wed, 26 Feb 2020, ToddAndMargo via perl6-users wrote: > > > $ p6 'say (99/70).base-repeating();' > > > (1.4 142857) > > > > > > means that 142857 also repeats (it does not), but > > > that it is best it can figure out with the precision > > > it has? > > > > > > > What are you talking about? It does repeat. I suggest you take a piece > > of paper and compute the decimal digits of 99/70 by hand until you are > > convinced that it is 1.4 and then an endless stream of 142857 repeating. > > I used gnome calculator to 20 digits: > 665857/470832 > 1.41421356237468991063 > Sorry. Not seeing any repeating patterns. > Todd, you were asking about 99/70, so I answered you about 99/70. I even quoted it. Now you come with 665857/470832. For that number, you will see the repetition after about 580 decimal digits. > Here is NAS doing it to 1 million digits (they have too > much time on their hands): > https://apod.nasa.gov/htmltest/gifcity/sqrt2.1mil > No repeats. > > So why does base-repeating tell me there is a repeating > pattern when there is not? > Sigh. We already settled that Rat and Num in Raku are rational numbers and that √2 is an irrational number. So what can you definitely not apply the base-repeating method to in Raku? -- The honest value of √2. NASA apparently computed the first million digits of √2 and you see no repeated digits. Good. In fact a real number is irrational if and only if its decimal expansion has no repeating pattern. You can view this as a reason for why they are not super easy to deal with on a computer. But that has nothing to do with the numbers we looked at above. Those were obviously rational numbers. They were obviously different from √2 because that number is not rational -- and we were looking at rational numbers. We were looking at rational numbers close to √2. What makes you think that NASA computing digits of the number √2 has any bearing on the correctness of `(99/70).base-repeating`? Because √2 and 99/70 are obviously not the same number. We are not working out the decimal expansion of √2. We are working out decimal expansions of rational numbers close to, but different from, √2. Even though they are close, structural properties of the expansions, like the existence of a repeating pattern, are radically different. > Ah ha, 99/70 does have a repeat: > 1.4142857 142857 142857 1 > > Maybe 665857/470832 I just do not go out enough digits to > see a repeat. > > √2 does not repeat though, but I am thinking that > I am stretching the poor machines abilities a bit too far > and that is where the repeat comes from > > $ p6 'say sqrt(2).Rat.base-repeating();' > >> (1.4 > >> 14213197969543147208121827411167512690355329949238578680203045685279187817258883248730964467005076) > > So, with the technology on hand, the approximation of √2 > does have a repeating pattern of > > 14213197969543147208121827411167512690355329949238578680203045685279187817258883248730964467005076 > > (And in engineering terms, is meaningless) > Yes, √2 has no repeating decimal pattern and the repetition returned to you is the one of the rational approximation to √2 that Raku computed when you asked for `sqrt(2).Rat`. (Somehow it seems like you understood halfway through writing your response but decided to keep the first half anyway. I don't know why.) > > > And what are the unboxing rules for (665857/470832)? > > > > > > > No idea what you mean. > > When is <665857/470832> unboxed to a Real number to > operate on it? Or is it never unboxed? > I'm no boxing expert, but I know that Rat has high-level arithmetic defined for it and there is no native rational type to unbox to. That would have to go through Num, I suppose. So I see neither a need nor a target for unboxing a Rat. But I still have no idea what kind of operations you have in mind. That said, Rat is not a NativeCall- related type. -- "There's an old saying: Don't change anything... ever!" -- Mr. Monk
Re: irrational nubmer?
On Wed, 26 Feb 2020, Todd Chester via perl6-users wrote: > Hi Tobias, > > I am confused as to as to what you mean by numerator and > denominator. > Rational numbers can always be written as the ratio of two integers: a/b with b non-zero. One calls a the numerator and b the denominator. In Raku the types Int, Rat, FatRat and Num are all rational numbers, as they all can be written as the ratio of two integers (up to Infs and NaNs). > When I say: > $ p6 'say (99/70).base-repeating();' > (1.4 142857) > > $ p6 'say (665857/470832).base-repeating();' > (1.4142 > 135623746899106262955788901349101165596221157440445849050192000543718353892683589900431576443402317599483467563801950589594590002378767798280490705814388146939885139497740170591633533829476331260407109117477146837937948142861997485302613246338396710503958949264281102388962517415978523125021238998198932952730485608454820403031229822951711013694906038671967920617120331668195874536989839263261630475413735684915213919189859652699901451048356951099330546776769633329935093621504060896455635980562068848336561661059571142148367145818466034594080266421993407414959051211472457267) > > $ p6 'say sqrt(2).Rat.base-repeating();' > (1.4 > 14213197969543147208121827411167512690355329949238578680203045685279187817258883248730964467005076) > > How does Raku know √2 is approximated by 99/70 or 665857/470832? > Does not Raku just throw a binary algorithm at any number you > feed sqrt? > The floating point unit in your computer receives the 2 and returns a floating point approximation of √2. Raku then uses the algorithm I linked to in my last email to give you the 99/70. > also, what exactly am I look at with (1.4 142857)? Is > this a way of saying that 1.4 is the rational part and > 142857 the irrational part? > No, Raku doesn't know anything about irrational numbers. As soon as you obtain the return value of `sqrt(2)` in Raku, you got a rational approximation to √2 and no part of the program knows that you wanted to compute an irrational number. The irrationality is gone, it was all in your head. You are dealing with this rational number that is "close" to √2. > What is also confusing is when a number does not repeat, > what is .base-repeating() trying to tell me? Is does not repeat? > > 2/3 is 0.666. > $ p6 'say (2/3).Rat.base-repeating();' > (0. 6) > > Does that mean that the 6 repeats? > Yes. > and > > $ p6 'say (99/70).base-repeating();' > (1.4 142857) > > means that 142857 also repeats (it does not), but > that it is best it can figure out with the precision > it has? > What are you talking about? It does repeat. I suggest you take a piece of paper and compute the decimal digits of 99/70 by hand until you are convinced that it is 1.4 and then an endless stream of 142857 repeating. If afterwards you trust Raku again, try `(99/70).base(10, 1000)` to get the first thousand decimal digits of that fraction printed. > And it it can not find a repeat, why does it not say so? > If you did the pen and paper exercise above, you know how the algorithm goes and that it is very easy to see when you've found the repeat and when you haven't. Above, there was a repeat that was easily found. The documentation says that if the repeat cannot be found within a thousand digits, the repeating part in the return value of &base-repeating will be "???". I've found this to be false. The source code of the method does not have such precautions and the limit is certainly not 1000 decimals. Try for example 1/1019 which has a group of 1018 repeating decimals. [ Maybe the number-theoretically inclined subscribers here will figure out how I found this example. ] Curiously, the old design docs [1] mandate a buffer of 100_000 to look for repeating digits. Pre-christmas versions of Rakudo apparently did have this check but "sanity", as a comment in the Rakudo sources called it, was removed in March 2015 [2] :-) As it currently stands [3], Rakudo will exhaust all memory to try to find the repeating group if it has to. (Note that all rational numbers have this repeating group -- you know this if you did the exercise -- so the search is never in vain, but it *is* attack surface for a DoS.) > And why am I getting zero back from > $ p6 'say sqrt(2).Rat.base-repeating() - (665857/470832).base-repeating();' > 0 > The return value of &base-repeating is a list. You are subtracting two lists which actually gets you the difference of their lengths. Since both lists have two elements (all lists returned by that function do) you get zero: > sqrt(2).Rat.base-repeating - sqrt(1000).Rat.base-repeating 0 > Also, what is the algebraic precedence of the operation? In > (665857/470832).base-repeating() > > is (665857/470832) solved first or is (665857/470832) a special > number (Rat) that is fed to .base-repeating? > What happens here is that the expression `665857/470832` is a Rat literal. You take this literal Rat object and call a method on it. It is not conv
Re: irrational nubmer?
On Thu, 20 Feb 2020, ToddAndMargo via perl6-users wrote: > > > On Fri, 21 Feb 2020 at 13:31, ToddAndMargo via perl6-users > > > mailto:perl6-users@perl.org>> wrote: > > > > > > $ perl6 -e 'say sqrt(2).base-repeating();' > > > No such method 'base-repeating' for invocant of type 'Num' > > > in block at -e line 1 > > > > > On 2020-02-20 19:07, Norman Gaywood wrote: > > > > perl6 -e 'say sqrt(2).Rat.base-repeating();' > > (1.4 > > 14213197969543147208121827411167512690355329949238578680203045685279187817258883248730964467005076) > > Hi Norman, > > Much better! > > Question: Rat: > https://docs.raku.org/type/Rat > > Rat objects store rational numbers as a pair > of a numerator and denominator. Number literals > with a dot but without exponent produce Rats. > > What does Rat do to sqrt(2) to give it a numerator > and a denominator? > I'm not sure if you have digested what others have said, so I'll repeat it: sqrt(2) already has a numerator and denominator. sqrt(2) takes the integer 2 and computes its square root as a floating point number using magic IEEE powder. If you look up the IEEE 754 float representations, you'll notice that every (non-NaN, non-Inf) float is a rational number. So sqrt(2) is already a rational number approximating the positive real number whose square is 2. That said, just taking the obvious numerator and denominator from the float might give you unnecessarily large numbers, and the Rat conversion on Num has to support a user-supplied tolerance as well. Reading the documentation, it seems that Raku does not require IEEE 754 to be in effect at all. So what Rakudo does (I recommend reading the source code [1]) is a variant of finding a continued fraction for the Num [2], except that it computes the Rat instead and stops when it reached the requested accuracy. It starts from scratch and iteratively approximates the Num, which has the advantage that you can stop when you don't have to continue and that it only relies on arithmetic on the Num working, not that it is represented according to some standard internally. Note also that Num.Rat supports a :fat argument to give you a FatRat back, but you cannot actually increase the precision of your rational approximation of √2 beyond the source you put in, which is a double precision float: > sqrt(2).Rat.nude # precision 1e-6, the default (1393 985) > sqrt(2).Rat(1e-8).nude # a bit better requested, request granted (19601 13860) > sqrt(2).Rat(1e-16).nude # still better but 1e-16 is ca. the limit (131836323 93222358) > sqrt(2).Rat(1e-20).nude # no improvement (131836323 93222358) > sqrt(2).Rat(1e-100, :fat).nude # fatter but not better, because (131836323 93222358) # the source sqrt(2) is too lossy Regards, Tobias [1] https://github.com/rakudo/rakudo/blob/cdbd60c1/src/core.c/Num.pm6#L46 [2] https://en.wikipedia.org/wiki/Continued_fraction#Calculating_continued_fraction_representations -- "There's an old saying: Don't change anything... ever!" -- Mr. Monk
Re: irrational nubmer?
On Wed, 19 Feb 2020, Paul Procacci wrote: > >> Is there a test to see if a number is irrational > There is no such thing as an irrational number in computing. > > Surely there are "close approximations", but that's the best any computer > language can currently do. > It all depends on representation. Of course there are ways to write algebraic numbers as their minimal polynomials over the rationals. You may not call that a "number", but you can do effective arithmetic with such a representation, so for many purposes it's as good as a "chunk of bits" number and it is an exact symbolic representation of a (possibly irrational) number from which you can extract rational approximations of any wanted precision. And in that representation, a number is irrational if and only if the minimal polynomial has degree at least two, very easy to check. (Note, however, that you do not get all irrationals in this way. π and e are still out of reach, for example.) Granted, Todd would not have anticipated this answer if he calls arbitrary length integers "magic powder" and the question "I have computed this Int/Num/Rat in Raku, is it rational?" does indeed not make any sense. But there are computer languages that can do better. Given FatRats, such modules can be written for Raku today. There seems to be a slogan of some sort that, if you search IRC logs or the documentation, pops up a number of times: "Perl 6 (Raku) is not a computer algebra system" ("RINACAS"?). I don't know what happened in the history of Perl 6 development, but it seems that irrationals were sought in core at some point and it was Larry who stopped that motion [1]. Regards, Tobias [1] https://github.com/Raku/problem-solving/issues/4#issuecomment-474892811 -- "There's an old saying: Don't change anything... ever!" -- Mr. Monk
Re: bytes are used in an UInt/Int?
On Mon, 03 Feb 2020, ToddAndMargo via perl6-users wrote: > Hi All, > > Did Larry put a sneaky way to tell how many bytes > a UInt/Int is using? > The number of bits required to store an Int is, for positive numbers, the same as the index of their most significant bit, which is available via Int.msb. From the bits, you can calculate the bytes. How much memory the implementation actually allocates is "none of your business" I suppose. And you get to decide how you want to treat zero and negative integers (the latter probably by taking their absolute value). Maybe you always want to add an imaginary sign bit as well. Also please note that UInt is not a datatype and there is no storage associated with it. UInt is the name of a property that a pre-existing Int object can satisfy or not, namely being greater than or equal to zero. There are no objects of type UInt. There are only Int objects that smartmatch UInt or variables with a UInt constraint. Regards, Tobias -- "There's an old saying: Don't change anything... ever!" -- Mr. Monk
Re: Hash Constraints w/in subset's
On Sat, 01 Feb 2020, Paul Procacci wrote: > Hey ladies/gents, > > How would one go about defining a subset of a Hash who's key's and values > are both constrained by something > > I've read https://docs.perl6.org/type/Hash and it does make mention of > constraining keys and values, but not within the context of a subset. > Before I go ripping my hair out, I want to make sure I'm doing things right. > > For instance, what if I want to define a subset that uses a Hash as it's > base class, in which I want to add the constraint that it's keys must be > strings yet it's values are constrained to only accept Int's? > You would make a subset of Hash if you are getting Hashes and you want to give some common code that checks the validity of the Hash a name. If you want a new type that you can actually create objects from, the solution is subclassing, not subsetting, but works similarly to below. (Just to make sure you're not surprised when you can't call .new on your subset later.) With a subset you could do: subset PhoneBook of Hash[Int, Str]; my Int %pb{Str}; %pb = +49_123_4567_6789; # good try %pb = "unknown"; # fails dd %pb #= Hash[Int,Str] %pb = (my Int %{Str} = :tobias(4912345676789)) say %pb ~~ PhoneBook #= True to the same effect. Note that if you subset PhoneBook of Hash[Int, Str], then your hashes really must be typed. An ordinary Hash that just happens to always map strings to integers is not sufficient and will fail the type check. You could make a looser subset of Hash with a where clause that checks compatibility of all keys with Str and of all values with Int as well, but that would be more expensive. To answer your question: Hash does the Associative role which is parameterized by the key and value type, but *in reverse order*. Hash[Int, Str] is the type that maps Int <-- Str, just like in the neat `my Int %pb{Str}` declaration. Regards, Tobias -- "There's an old saying: Don't change anything... ever!" -- Mr. Monk
Re: stolen uint's
On Tue, 28 Jan 2020, ToddAndMargo via perl6-users wrote: > This all came up when I tried to match > > RegSetValueExW( > _In_ HKEY hKey, > _In_opt_ LPCWSTR lpValueName, > _Reserved_ DWORD Reserved, > _In_ DWORD dwType, > _In_reads_bytes_opt_(cbData) CONST BYTE * lpData, > _In_ DWORD cbData > > where CbData can either be a UTF little endian C string, > terminated by a nul or a four byte little endian > unsigned integer (no two's complement allowed) depending > on the value of lpValueName (REG_SZ, REG_DWORD, etc.) > > I wound up doing this: > > subset StrOrDword where Str | UInt; > sub WinRegSetValue( WinRegHives $Hive, Str $SubKey, Str $KeyName, ValueNames > $ValueType, StrOrDword $ValueData, Bool $Debug = False ) > returns DWORD is export( :WinRegSetValue ) { Are you really 100% sure that you interpreted this API correctly? I see how a DWORD cbData can be a four-byte unsigned integer: it gives the length of lpData in bytes, as documented [1]. But then a DWORD is 4 bytes long. Reusing these 4 bytes for an alternative interface where you may pass a UTF-whatever string that is at most 4 bytes encoded, including the NUL terminator... seems too insane. And there is no mention of that in the documentation page [1]. I do not think that cbData is ever used for anything but to indicate the length of the buffer lpData. It is lpData which can have a multitude of types (and serialization formats), the intended one to be taken from the dwType argument (not lpValueName). My advice is still the same I gave in my very first reply to this thread: make your function a multi and write a candidate for each dwType. You have to write different code for serializing an integer vs. a string to pass as lpData anyway and the compiler can detect native types in multi dispatch for you: # REG_DWORD multi WinRegSetValue(…, uint32 $data) { use experimental :pack; RegSetValueExW(…, REG_DWORD, pack("L", $data), 4) } # REG_SZ multi WinRegSetValue(…, Str $data) { my $blob = "$data\0".encode RegSetValueExW(…, REG_SZ, $blob, $blob.bytes) } # REG_BINARY multi WinRegSetValue(…, blob8 $data) { RegSetValueExW(…, REG_BINARY, $data, $data.bytes) } Regards, Tobias [1] https://docs.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regsetvalueexw -- "There's an old saying: Don't change anything... ever!" -- Mr. Monk
Re: Range on Subsets
On Tue, 28 Jan 2020, Simon Proctor wrote: > So some recent conversations covered the Range method on numeric types like > Int > > So Int.Range gives the range of valid values -Inf^..^Inf which is neat. > > Then I thought I'd try UInt.Range and got 0..^Inf > > Ah Ha! Thinks I. I have a plan. What if I try this? > > my subset OneToTen of Int where { not .defined or 1 <= $_ <= 10 }; > say OneToTen.Range; > > And it gives ... > > -Inf^..^Inf > > And now I'm a bit confused. The Docs say the UInt is just a subset > https://docs.raku.org/type/UInt > > So how does it have it's own Range? > It's simply special-cased in the Int.Range implementation: https://github.com/rakudo/rakudo/blob/d8e859d000fa658766266a45f99e58661dec7b0e/src/core.c/Int.pm6#L239 As a consequence of the implementation checking the .^name, you can make Rakudo appear very confused: subset UInt of Int where 1000 .. 1002; say UInt.Range; #= 0..^Inf Arguably, the subset declarator could probably make the case where the matcher is an explicit Range as above DWIM, but as soon as arbitrary code is involved, as in your OneToTen, there is no hope to make a sensible Range method. Regards, Tobias -- "There's an old saying: Don't change anything... ever!" -- Mr. Monk
Re: stolen uint's
On Sat, 25 Jan 2020, ToddAndMargo via perl6-users wrote: > Hi All, > > Anyone have a workaround to my stolen uint's? > > > constant DWORD := uint32; > (uint32) > > > subset StrOrDword where Str | DWORD; > (StrOrDword) > > > sub x( StrOrDword $item ) { > * say "$item is a " ~ $item.^name; > * } > &x > > > x( "abc" ); > abc is a Str > > > x( 3 ); > Constraint type check failed in binding to parameter '$item'; expected > StrOrDword but got Int (3) > in sub x at line 1 > in block at line 1 > > > x( 3.UInt ); > Constraint type check failed in binding to parameter '$item'; expected > StrOrDword but got Int (3) > in sub x at line 1 > in block at line 1 > Raku allows you to use native datatypes and to constrain variables to refuse anything but some kind of native data. But an uint32 is just 32 bits, no class and no methods attached. If nevertheless you call methods on native values, they will be boxed into objects that actually support methods to be called on themselves. Native integers, signed or not, are boxed into Int. With that in mind, re-read the documentation section about native dispatch [1]. Your sub x has no candidate that statically accepts a native integer. Since you use a subset type, the typecheck is deferred until runtime, but StrOrDword.ACCEPTS has no native integer candidate either, and at that point you lost already, as x(my uint32 $ = 3) would result in the 3 being auto-boxed to be able to check it against `Str | uint32` and because of the boxing, its type is now Int and the check fails. Consider: sub x(uint32 $item) { say "$item is a " ~ $item.^name } x(3);# works, `only` subs auto-unbox the Int literal x(my uint32 $ = 3); # works, a native integer is provided In both cases, "3 is a Int" will be printed, because the class name is obtained by calling a (meta-)method on $x, which triggers boxing to Int. There is no room for a class name in a 32 bits native integer. Now, if you change the signature to something subsetty/dynamic like sub x($item where uint32) both calls fail to dispatch, as explained above. On the other hand, this works because there is an explicit native integer candidate for the dynamic typecheck, so you don't get boxed: sub x($item where -> uint32 { True }) By the way, this has nothing to do with unsigned or signed integers, your signs are not stolen, your values are boxed. The uint32 type is simply not suitable to be typechecked against, as this quintessentially paradoxical line of code tells you: say (my uint32 $ = 3) ~~ uint32; # False Native data is second-class data in a language where everything is an object. If you want a workaround, eschew the subset and provide two candidates for your sub x: one for Str and one for uint32. How do you expect to handle something that may either be a Raku string object or a native integer in a single candidate anyway? Or drop the native integer altogether and use Int until you really need the native thing. Regards, Tobias [1] https://docs.raku.org/language/numerics#Native_dispatch -- "There's an old saying: Don't change anything... ever!" -- Mr. Monk
Re: troubles with with base(2)
On Mon, 20 Jan 2020, ToddAndMargo via perl6-users wrote: > Hi All, > > Now what am I doing wrong? > > my $v = 0b00101101 ^ 0b1001; say $v.base(2); > one(101101, 1001) > > It should be > 100100 > Please examine the output you get. Does the spurious "one" in there not make you raise an eyebrow and head over to the documentation? ^ is a junction constructor, specifically it creates a one() junction. If you want bitwise XOR use the... bitwise XOR operator +^. In general, the "bare" operators &, |, ^ in Raku are used for declarative purposes: in normal Raku they are junction constructors and in regexes they denote longest-token matching. Many other languages use these operators for (signed or unsigned) bitwise operations, but in Raku these "numeric" bitwise operations are put under the "+" umbrella to show that they are numeric: +&, +| and +^. Corresponding operators also exist for buffers as ~&, ~| and ~^, for booleans as ?&, ?| and ?^ and for sets as (&), (|), (^). This is a truly beautiful and thoughtful thing about Raku. Regards, Tobias -- "There's an old saying: Don't change anything... ever!" -- Mr. Monk
Re: my first two doc issues
On Sun, 19 Jan 2020, ToddAndMargo via perl6-users wrote: > RFE: Please add the following examples to routine +^ > https://github.com/Raku/doc/issues/3177 > > Now I wait and see what kind of reception I get. It > will be nice to contribute to the docs, rather than > just always griping about them > Oh well, I just responded with what my gut told me when this arrived in my inbox. Didn't know that I would be part of a public experiment. Anyway, godspeed! Regards, Tobias -- "There's an old saying: Don't change anything... ever!" -- Mr. Monk
Re: Ping JJ: string literals
On Sat, 18 Jan 2020, ToddAndMargo via perl6-users wrote: > > > Would you be so kind to post this as an issue in the documentation, so > > we can pick up on it? > > > > Thanks! > > > > JJ > > Would you mind posting back the link to it, so I can > get on the following list? https://github.com/Raku/doc/issues/3169 -- "There's an old saying: Don't change anything... ever!" -- Mr. Monk
Re: problems with xor
On Fri, 17 Jan 2020, ToddAndMargo via perl6-users wrote: > Hi All, > > https://docs.raku.org/routine/+$CIRCUMFLEX_ACCENT > > (Operators) infix +^§ > > multi sub infix:<+^>($a, $b --> Int:D) > > Integer bitwise XOR operator: Coerces both arguments to Int and does a > bitwise XOR (exclusive OR) operation. > > > $ p6 'my uint8 $x=0b0101_0111; my uint8 $y = 0b_; my uint8 $z = > +^($x, $y ); say "0", $x.base(2); say "", $y.base(2); say $z.base(2);' > > 01010111 > > 1101 > > > XOR > A B A xor B > 0 0 0 > 1 0 1 > 0 1 1 > 1 1 0 > > That s not what I am seeing above. > > What am I doing wrong this time? > > And who set the high bit making $z negative? > As was already mentioned, if you want to use the &infix:<+^> operator, you have to either call it by its full name as a sub: &infix:<+^>($x, $y) or you have to use it according to its syntax category, as an infix: $x +^ $y When you write +^($x,$y), its cousin &prefix:<+^> is called instead, because now you use +^ as a prefix operator. That one performs bitwise negation on its argument coerced to Int, and since you pass it a list of length two, you actually evaluate +^2. And that's how you get the high bit and a value of -3. Regards, Tobias -- "There's an old saying: Don't change anything... ever!" -- Mr. Monk
Re: Ping JJ: string literals
On Sat, 18 Jan 2020, JJ Merelo wrote: > The example works perfectly, and it does because it's a string literal > which is already 0 terminated. Let's use this code instead of the one that > I used in my other mail about this (which you probably didn't read anyway): > > 8< 8< 8< > > What does this mean? It means that NativeCall does the right call > (badum-t) and converts a Raku string literal into a C string literal, > inserting the null termination even if we didn't. I actually don't care if > it was the NativeCall API or the encode method. It just works. It gets > allocated the right amount of memory, it gets passed correctly into the C > realm. Just works. Since @array.elems has 3 elements, well, it might be > rather the C part the one that does that. But I really don't care, and it > does not really matter, and thus the example is correct, no need to add > anything else to the documentation. Except maybe "get your C right" > What you say seems to be correct: if you have a string literal in your Raku code, this works for me, too. (Sometimes, see below.) BUT the terminating NUL character is not inserted by NativeCall and it isn't inserted by &encode. If you run this program which uses a much longer string that is not a literal on the face of it: use NativeCall; sub c-printf(CArray[uint8]) is native is symbol { * }; my $string = "X" x 1994; my $array = CArray[uint8].new($string.encode.list); c-printf $array; through valgrind, it will warn you about a one-character invalid read, that is a byte accessed by printf() which is at offset 0 after a properly allocated block of size 1994: $ perl6-valgrind-m -MNativeCall -e 'sub c-printf(CArray[uint8]) is native is symbol { * }; my $string = "X" x 1994; my $array = CArray[uint8].new($string.encode.list); c-printf $array' >/dev/null ==325957== Invalid read of size 1 ==325957==at 0x48401FC: strchrnul (vg_replace_strmem.c:1395) ==325957==by 0x50CD334: __vfprintf_internal (in /usr/lib/libc-2.30.so) ==325957==by 0x50BA26E: printf (in /usr/lib/libc-2.30.so) ==325957==by 0x4B58048: ??? (in $rakudo/install/lib/libmoar.so) ==325957==by 0x1FFEFFFB5F: ??? ==325957==by 0x4B57F81: dc_callvm_call_x64 (in $rakudo/install/lib/libmoar.so) ==325957==by 0x50BA1BF: ??? (in /usr/lib/libc-2.30.so) ==325957==by 0xA275E3F: ??? ==325957==by 0x990153F: ??? ==325957==by 0xA275E3F: ??? ==325957==by 0x1FFEFFFB7F: ??? ==325957==by 0x4B578D1: dcCallVoid (in $rakudo/install/lib/libmoar.so) ==325957== Address 0xb5ebf1a is 0 bytes after a block of size 1,994 alloc'd ==325957==at 0x483AD7B: realloc (vg_replace_malloc.c:836) ==325957==by 0x4A9DFDF: expand.isra.3 (in $rakudo/install/lib/libmoar.so) ==325957==by 0x4A9E6F4: bind_pos (in $rakudo/install/lib/libmoar.so) ==325957==by 0x4A2C9AF: MVM_interp_run (in $rakudo/install/lib/libmoar.so) ==325957==by 0x4B2CC24: MVM_vm_run_file (in $rakudo/install/lib/libmoar.so) ==325957==by 0x109500: main (in $rakudo/install/bin/perl6-m) This is the NUL byte that happens to be there and terminate our string correctly, but nothing in the moarvm process has allocated it, because knowing what is allocated and what isn't is valgrind's job. And if it's not allocated, then either moarvm routinely writes NULs to memory it doesn't own or it simply does not automatically insert a NUL after the storage of every CArray[uint8]. And why would it? I for one would not expect CArray[uint8] to have special precautions built in for when it's used to hold a C string. Why does it work with a string literal in the Raku code? I don't know, but consider the following variations of the code, with my oldish Rakudo: - with $string = "X" x 1994: valgrind sad - with $string = "X" x 4:valgrind sad - with $string = "X" x 3:valgrind happy - with $string = "X" x 2:valgrind happy - with $string a short literal like "FOO":valgrind happy - with $string a literal of sufficient length like "FOOO": valgrind sad - with $string = "FOO" x 2: valgrind happy - with $string = "FOO" x 200:valgrind sad My guess is that if it's sufficiently small and easy, then it is computed at compile-time and stored somewhere in the bytecode, for which some serialization routine ensures a trailing NUL byte inside an allocated region of memory for the process. That is only a barely informed guesses, but independently of what causes it to work on short string literals, I strongly believe that this is an implementation detail and hence I would call the example in the docs misleading. Appending the ", 0" when constructing the CArray[uint8] seems like a really neat fix. Anyway, the most important message of this mail should actually be: _Normally_, the way you pass a Raku string to a native function is by using the `is encoded` trait. It's such a nice
Re: Cardinals
On Thu, 02 Jan 2020, ToddAndMargo via perl6-users wrote: > Hi All, > > “He who asks is a fool for five minutes, but he who > does not ask remains a fool forever.” > ― Mark Twain > > This would be my five minutes. I will live. > > How do I do a 32 bit unsigned integer (cardinal)? I > have a situation where I need to be able to have the > first bit be a one and not have Raku think it is > a negative number. > It's called uint32: https://docs.perl6.org/language/nativetypes#index-entry-uint32 -- "There's an old saying: Don't change anything... ever!" -- Mr. Monk
Re: play with raku and autobiographical numbers
On Tue, 31 Dec 2019, Marc Chantreux wrote: > hello, > > 2020 describes itself as it is composed by > > 2 0 > 0 1 > 2 2 > 0 3 > > perfect golf excuse! I have : > > sub is_autobiographic (\x) { > my \s = x.Str; > my @r = s.comb; > my %appearance_of; > %appearance_of{$_}++ for @r; > x ~~ join '', (%appearance_of{$_}//0 for 0..^@r); > } > > (^∞ > ).race( :1batch,:10degree > ).grep( &is_autobiographic > ).head(10).map(*.say) > > anyone with something simpler? > Here is my entry, having a Bag count the occurences of letters, instead of the loop over @r you used. It also doesn't assemble a string out of the bag to compare the input to, but consults the bag directly for each digit: sub is-autobiographic (\x) { my \bag = x.comb.Bag; [and] x.comb.kv.map: { bag{~$^i} == $^v } } Regards, Tobias -- "There's an old saying: Don't change anything... ever!" -- Mr. Monk
Re: square root question
On Sat, 14 Dec 2019, ToddAndMargo wrote: > What am I doing wrong here? > > > multi prefix:<√> (Cool:D $x) { $x.sqrt } > &prefix:<√> > > > say √2 > ===SORRY!=== > Argument to "say" seems to be malformed > --> say⏏ √2 > Bogus postfix If this is inside the REPL, it's not your fault. It's a known issue: https://github.com/rakudo/rakudo/issues/2245 Regards, Tobias -- "There's an old saying: Don't change anything... ever!" -- Mr. Monk
Re: about 'use v6.d'
On Fri, 13 Dec 2019, Brad Gilbert wrote: > There should probably be a way to require a minimum version of the compiler. > > use rakudo v2019.07; > As I understand it, this would do something quite different from `use v6`, which is probably your point(?). A single Raku compiler would strive to support `use v6.x` for many x, which Rakudo does by keeping around a setting for each language version. The `v6` pragmas can be changed per compunit under the same compiler, so different parts of the same process can run under different Raku versions. (You probably know that more accurately than me, so please correct me if I'm wrong.) What Rakudo doesn't do is include a setting for every release, so the effect of a `use rakudo v2019.07` would be closer to a *dependency* rather than a pragma: it doesn't change the way your code is executed, it will abort it altogether if your compiler is not recent enough or not Rakudo. My under- standing is that META6.json would be the natural place to declare dependencies, although I couldn't tell how to properly declare a compiler dependency there, as the compiler is not a module (right?). Otherwise such a rakudo pragma is probably as easy to implement as --8<-- rakudo.pm6 sub EXPORT (Version:D $ver) { given $*PERL.compiler { die "This compiler is not Rakudo"unless .name eq 'rakudo'; die "Rakudo version ≥ $ver required" unless .version ≥ $ver; } %( ) } --8<-- Regards, Tobias -- "There's an old saying: Don't change anything... ever!" -- Mr. Monk
Re: My keeper on "contains"
On Mon, 09 Dec 2019, perl6-users-h...@perl.org wrote: > Date: Sun, 8 Dec 2019 17:45:22 -0800 > From: ToddAndMargo via perl6-users > To: perl6-users > Subject: My keeper on "contains" > > 8< ... > > Case insensitive contains: > $ p6 'if "2018 Jul 7".fc.contains( "jul".fc ) {say "Yes";}' > Yes > > $ p6 'if "2018 xJul 7".fc.contains( "jul".fc ) {say "Yes";}' > Yes > > p6 'if "2018 xul 7".fc.contains( "jul".fc ) {say "Yes";}' > > > $ p6 'my $x="strong>2018.2.0; Coming Soon"; say so > $x.fc.contains("strong" & not "coming soon");' > False > Careful about the last example, it is misleading. The `not` in `"strong" & not "coming soon"` is not a junction constructor but is evaluated eagerly, resulting in this junction: $ rk 'dd "strong" & not "coming soon"' all("strong", Bool::False) because not("coming soon") is False at the moment where the & operator assembles the all-junction. The result of passing this to .contains will always be False, e.g. $ rk 'say so "strong".contains("strong" & not "weak")' False What you meant was $ rk 'say so "strong".contains("strong" & none "weak")' True which sadly doesn't sound as natural in English. Regards, Tobias PS: Sorry for not replying in-thread. I just registered and didn't have a proper copy of the mail at hand. (When I read about the "get" command of the mailing list manager, I got my hopes up too high apparently as I just received the mail canned in a digest, not suitable for replying.) -- "There's an old saying: Don't change anything... ever!" -- Mr. Monk