Re: Language Design: 'special casing' of split()? (i.e. .split performs concomitant .join? )
Dear Brad, Thank you so much for taking the time to reply! I wrote a few notes inline, below: On Sat, Oct 10, 2020 at 4:07 PM Brad Gilbert wrote: > > Functions in Raku tend to have one job and one job only. > > `split` splits a string. > > So if you call `split` on something that is not a string it gets turned into > one if it can. > > This happens for most functions. > > Having `split` be the only function that auto-vectorizes against an array > would be very confusing. I think the question I have is why string "auto-joining" is proverbially so 'high-up on the food chain'. I've understood that Perl (and by extension, Raku) has historically been a 'list-processing" language--that the language is centered on lists. So I expected that if you call a function on a single-element scalar, the function acts on that one element. I expected that if you call a function on a multi-element list, the function acts on every single element individually. (Obviously I'm glossing over the differences between Raku's multi-element $-sigilled scalars and @-sigilled arrays). > If it isn't the only function, then you have to come up with some list of > functions which do vectorize. > > Then every single person has to memorize that list in its entirety. Which can > be difficult even for experts. > > Perl has a similar list of functions which automatically work on `$_`, and > almost no one has that list memorized. > Raku very specifically did not copy that idea. > > --- > > Raku instead has high level concepts that it uses consistently. > > One of those concepts is that functions have one job and one job only. > > So if you call `chars` on anything it gets turned into a string first. > This is where my previous question on "language-paradigm priority" comes into play. Here I'm applying what I know from the (functional) R-programming language, where you choose a data structure based upon your input data. Have an ordered/unordered mixed sequence of letters/numbers? Use a vector. Have many vectors of varying length that are somehow all related to one another? Use a list. Have related vectors of the same length (rectangular data, i.e. database row)? Use a matrix or dataframe. Below, R-code (in the R-REPL) working on the built-in "letters" vector: > letters [1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l" "m" "n" "o" "p" "q" "r" "s" "t" "u" "v" "w" "x" "y" "z" > cat(letters) a b c d e f g h i j k l m n o p q r s t u v w x y z > length(letters) [1] 26 > is.vector(letters) [1] TRUE > mode(letters) [1] "character" > nchar(letters) [1] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 > nchar(paste0(letters, collapse="")) [1] 26 > Above, I call nchar() on a vector and I get back the number characters for each element of the list by default. We can think about the R-vector (analogous to a Raku array) driving the interchange when acted upon by R-functions. I think R's behavior makes sense when you try to call a mathematical function. The data structure dictates the return, and the bare math-function call gives the desired/expected return whether the function (e.g. cos) is called on a single-element or a vector of elements: > cos(2*pi) [1] 1 > cos(0:6 * pi) [1] 1 -1 1 -1 1 -1 1 Thanks, Bill. PS. If Raku's split() is string-only, what splits on bytes in Raku? What splits a file into multiple equal-sized files in Raku? Thx. https://www.theunixschool.com/2012/10/10-examples-of-split-command-in-unix.html > On Sat, Oct 10, 2020 at 4:23 PM William Michels via perl6-users > wrote: >> On Tue, Oct 6, 2020 at 1:59 PM Tobias Boege wrote:
Re: Language Design: 'special casing' of split()? (i.e. .split performs concomitant .join? )
Oh, thanks, now it makes sense. On Wed, Oct 14, 2020 at 12:01 PM Brian Duggan wrote: > On Wednesday, October 14, Aureliano Guedes wrote: > > In this point, the unique weirdness I'd like to understand is why in Raku > > `@nums.log == 2.302585092994046e0`. I don't understand where this value > > comes from. > > This comes from the length of the array; the array is coerced into a > numeric > value: > > > my @nums = 1..10 > [1 2 3 4 5 6 7 8 9 10] > > @nums.log > 2.302585092994046 > > @nums.Numeric.log > 2.302585092994046 > > 10.log > 2.302585092994046 > > Brian > -- Aureliano Guedes skype: aureliano.guedes contato: (11) 94292-6110 whatsapp +5511942926110
Re: Language Design: 'special casing' of split()? (i.e. .split performs concomitant .join? )
On Wednesday, October 14, Aureliano Guedes wrote: > In this point, the unique weirdness I'd like to understand is why in Raku > `@nums.log == 2.302585092994046e0`. I don't understand where this value > comes from. This comes from the length of the array; the array is coerced into a numeric value: > my @nums = 1..10 [1 2 3 4 5 6 7 8 9 10] > @nums.log 2.302585092994046 > @nums.Numeric.log 2.302585092994046 > 10.log 2.302585092994046 Brian
Re: Language Design: 'special casing' of split()? (i.e. .split performs concomitant .join? )
I'd like to help with my 2 cents. Given your comparison with R, sum, and mean are expected to play with a vector rather than log and sin are expected to play with single numbers. Then, the expected behavior for numerics types in Raku still the same as in R. The difference is only that the functions in Raku are designed to one and only one single function. #RAKU > my @nums = 0,1,2,3,4,5,6,7,8,9; [0 1 2 3 4 5 6 7 8 9] > @nums.sum 45 > sum(@nums) 45 #R > library(tidyverse) #import pipe %>% > nums <- 0:9 > nums [1] 0 1 2 3 4 5 6 7 8 9 > sum(nums) [1] 45 > nums %>% sum() [1] 45 > nums %>% log [1] -Inf 0.000 0.6931472 1.0986123 1.3862944 1.6094379 1.7917595 [8] 1.9459101 2.0794415 2.1972246 > log(nums) [1] -Inf 0.000 0.6931472 1.0986123 1.3862944 1.6094379 1.7917595 [8] 1.9459101 2.0794415 2.1972246 In this point, the unique weirdness I'd like to understand is why in Raku `@nums.log == 2.302585092994046e0`. I don't understand where this value comes from. In the case of strings, pay attention to the size of the array. The infix `>>` act as expected keeping the vector with the same size, which is the default behavior of R, since it is functional and vectorization is arguably its philosophy which handles very well data analysis which is its purpose. > @monsters>>.split(" ").elems 5 > @monsters.split(" ").elems 7 > my @monsters = << blob 'king kong' mothera fingfangfoom 'foo bar'>>; [blob king kong mothera fingfangfoom foo bar] > @monsters.elems 5 > @monsters.split(" ") (blob king kong mothera fingfangfoom foo bar) > @monsters.split(" ").elems 7 > @monsters>>.split(" ") [(blob) (king kong) (mothera) (fingfangfoom) (foo bar)] > @monsters>>.split(" ").elems 5 The point is, I don't know why Raku is designed the way it is. But is easier to implement in Raku the use of functional and vectorized paradigms than in Python which requires an external lib (e.g. Pandas or numpy). Of course, it might be better if Raku has docs explain the paradigms and philosophy behind the scenes and very didactic and well-explained docs as Perl5. Also, coping R, might be too inviting to learners and seniors if we had online handbooks, wiki-style docs, and cheat sheets as we have in R. best On Wed, Oct 14, 2020 at 3:28 AM William Michels via perl6-users < perl6-us...@perl.org> wrote: > On Mon, Oct 12, 2020 at 10:02 AM Larry Wall wrote: > > > > On Mon, Oct 12, 2020 at 01:14:09PM -0300, Aureliano Guedes wrote: > > : > This seems pretty convenient and intuitive. At least, it is possible > > : > to mimic that behavior in Raku: > > : > > > : > List.^find_method('split').wrap: { $^a.map: *.split($^b) } > > : > List.^find_method('sin').wrap: *.map: *.sin; > > : > > > : This is like overwrite the function? > > : Might be better just implement a new function, I mean, a new verb as is > > : called in R. > > > > In Raku these functions already have names, if you count metaoperators > as a fancy > > way to name anonymous functions: > > > > say ».split(','); > > say (0, (π/2, 3 * π/2))».sin; > > > > ((a b) (c d)) > > (0 (1 -1)) > > > > As shown by the ».sin example, unary hypers will distribute over > > multi-dimensional structures for you, just as an APL or R programmer > > would expect. But that behavior is not intuitively obvious to everyone, > > so the vector-processing paradigm is not the default. (But we make it > > really easy to get to when you want it, as you can see. And arguably > > the explicit presence of » or >> makes your intent clearer to the naïve > > reader, who at least has something to look up or ask about if they don't > > understand it.) > > > > Larry > > Hi Larry! > > First of all, let me thank you for designing the Raku (née Perl6) > programming language in the first place. I've really enjoyed learning > a different set of programming paradigms than I was previously > accustomed to. > > With regards to the present topic, what initially 'disunited' me was > calling split() on an a array and ending up with joined elements. It > becomes most apparent when one tries to split() on a character that > isn't present in the array in the first place--in that case, all array > elements are joined into a single string. It has been explained to me > that arrays coercible to strings and called with a string-function > *are* auto-joined with a single space as separator, but it would be > nice to control this behavior somewhat, e.g. for generating a CSV line > (join on commas instead of spaces). > > However. I guess the real question in my mind is how to predict which > function "verbs" will work on array "nouns" in plural form (I'm daring > here to discuss linguistics with a linguist). Certainly we know nouns > that remain invariant from singular to plural (sheep, fish, deer, > salmon, aircraft and other -craft, etc.). These nouns exist and don't > seem to be going away anytime soon. I can say "Eels fill my > hovercraft," and that one statement applies to both singular and >
Re: Language Design: 'special casing' of split()? (i.e. .split performs concomitant .join? )
On Mon, Oct 12, 2020 at 10:02 AM Larry Wall wrote: > > On Mon, Oct 12, 2020 at 01:14:09PM -0300, Aureliano Guedes wrote: > : > This seems pretty convenient and intuitive. At least, it is possible > : > to mimic that behavior in Raku: > : > > : > List.^find_method('split').wrap: { $^a.map: *.split($^b) } > : > List.^find_method('sin').wrap: *.map: *.sin; > : > > : This is like overwrite the function? > : Might be better just implement a new function, I mean, a new verb as is > : called in R. > > In Raku these functions already have names, if you count metaoperators as a > fancy > way to name anonymous functions: > > say ».split(','); > say (0, (π/2, 3 * π/2))».sin; > > ((a b) (c d)) > (0 (1 -1)) > > As shown by the ».sin example, unary hypers will distribute over > multi-dimensional structures for you, just as an APL or R programmer > would expect. But that behavior is not intuitively obvious to everyone, > so the vector-processing paradigm is not the default. (But we make it > really easy to get to when you want it, as you can see. And arguably > the explicit presence of » or >> makes your intent clearer to the naïve > reader, who at least has something to look up or ask about if they don't > understand it.) > > Larry Hi Larry! First of all, let me thank you for designing the Raku (née Perl6) programming language in the first place. I've really enjoyed learning a different set of programming paradigms than I was previously accustomed to. With regards to the present topic, what initially 'disunited' me was calling split() on an a array and ending up with joined elements. It becomes most apparent when one tries to split() on a character that isn't present in the array in the first place--in that case, all array elements are joined into a single string. It has been explained to me that arrays coercible to strings and called with a string-function *are* auto-joined with a single space as separator, but it would be nice to control this behavior somewhat, e.g. for generating a CSV line (join on commas instead of spaces). However. I guess the real question in my mind is how to predict which function "verbs" will work on array "nouns" in plural form (I'm daring here to discuss linguistics with a linguist). Certainly we know nouns that remain invariant from singular to plural (sheep, fish, deer, salmon, aircraft and other -craft, etc.). These nouns exist and don't seem to be going away anytime soon. I can say "Eels fill my hovercraft," and that one statement applies to both singular and plural hovercraft. But swapping the statement around to the more familiar, we clearly see the verb lets us know whether hovercraft is used in the sigular or plural: "My hovercraft is/are full of eels." Thinking of Raku arrays as invariant nouns, I might wonder which "verb" functions denote acting on a 'singular' array (acting on the array as a whole) versus acting on a 'plural' array (i.e. acting element-by-element). Without consulting the Docs, in regards to functions acting wholly or primarily on strings, I might guess that the 'grep()' verb acts on a 'singular' array. From my previous posts you can gather I guessed that split() acts element-by-element on a 'plural' array (along with many other string functions). Without consulting the Docs, in regards to numeric-functions I might guess that the sum() verb and any 'mean()' verb would act on a 'singular' array, and I'd guess that most other numeric functions like log() and sin() would act element-by-element on a 'plural' array. This could be completely off-base, and a consequence of sum() or mean() being 'many-to-one' functions, while log() and sin() etc. have a 1-to-1 input/output correspondence. Now maybe this is a road that has been trodden before, with Perl. Or maybe it's my own linguistic preconceptions getting in the way. But I really do hope to understand why the Raku language is designed the way it is designed. Thanks, Bill. > #REPL code below: Nil > my @monsters = << blob 'king kong' mothera fingfangfoom >>; [blob king kong mothera fingfangfoom] > dd @monsters Array @monsters = ["blob", "king kong", "mothera", "fingfangfoom"] Nil > @monsters.grep(/" "/); (king kong) > @monsters>>.grep(/" "/); (() (king kong) () ()) > dd @monsters.split(" "); ("blob", "king", "kong", "mothera", "fingfangfoom").Seq Nil > dd @monsters>>.split(" "); Array element = [("blob",).Seq, ("king", "kong").Seq, ("mothera",).Seq, ("fingfangfoom",).Seq] Nil > my @nums = 0,1,2,3,4,5,6,7,8,9; [0 1 2 3 4 5 6 7 8 9] > dd @nums Array @nums = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] Nil > dd @nums.sum 45 Nil > dd @nums>>.sum (0, 1, 2, 3, 4, 5, 6, 7, 8, 9) Nil > dd @nums.log 2.302585092994046e0 Nil > dd @nums>>.log Array element = [-Inf, 0e0, 0.6931471805599453e0, 1.0986122886681098e0, 1.3862943611198906e0, 1.6094379124341003e0, 1.791759469228055e0, 1.9459101490553132e0, 2.0794415416798357e0, 2.1972245773362196e0] Nil >
Re: Language Design: 'special casing' of split()? (i.e. .split performs concomitant .join? )
Here's another way of phrasing these answers- Some routines like "join" operate on strings, and thus coerce their argument to a string. Some routines like "sin" operate on numbers, and thus coerce their argument to a number. Each class defines how it coerces to Str or Num, regardless of what is doing the coercing. Array defines its Str coersion as *.join(' ') and its Num coercion as *.items Sometimes those coercions are very helpful, like letting "put" write string representations of all sorts of things with no extra work for the developer. Other times, they are not so helpful, instead be explicit what you want the routine to work on- don't rely on coercion to the string or num the routine expects. With arrays, follow Larry's advice and use the >> hyperoperator, if that's what you want. There's no "context" in the Perl sense, that history refers to a "wantarray" built-in where a subroutine would ask if the return value was assigned to an array or not, and then behave differently. Raku doesn't have that. https://docs.raku.org/language/5to6-perlfunc#index-entry-wantarray_-_perlfunc -y On Mon, Oct 12, 2020 at 6:44 PM William Michels via perl6-users < perl6-us...@perl.org> wrote: > > > On Sat, Oct 10, 2020 at 4:49 PM Tobias Boege wrote: > >> 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 >> > > > Thank you, Tobias! > > user@mbook~$ raku #test numeric function calls on array > user@mbook~$ raku #enter REPL > To exit type 'exit' or '^D' > > my @nums = 0, π/2, 3 * π/2; > [0 1.5707963267948966 4.71238898038469] > > say @nums.elems > 3 > > say @nums.sin.elems > 1 > > say @nums.sin > 0.1411200080598672 > > say @nums.elems.sin > 0.1411200080598672 > > say sin(3) > 0.1411200080598672 > > $*VM > moar (2020.06) > > > > At first perusal one might conclude that calling .sin on an array > "auto-joins" the arrays elements, but in fact, calling .sin on an array > returns the sin() of the number of array elements. The two calls > "@nums.sin" and "@nums.elems.sin" give exactly the same result. > > I'm ignorant of the 'historically charged' use of the term 'context', > although I interpret your comment to suggest that the term 'context' now > may be a disfavored concept. If so, then all the more reason to obviate the > need to explain this concept to new Raku programmers. > > --Best, Bill. >
Re: Language Design: 'special casing' of split()? (i.e. .split performs concomitant .join? )
On Sat, Oct 10, 2020 at 4:49 PM Tobias Boege wrote: > 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 > Thank you, Tobias! user@mbook~$ raku #test numeric function calls on array user@mbook~$ raku #enter REPL To exit type 'exit' or '^D' > my @nums = 0, π/2, 3 * π/2; [0 1.5707963267948966 4.71238898038469] > say @nums.elems 3 > say @nums.sin.elems 1 > say @nums.sin 0.1411200080598672 > say @nums.elems.sin 0.1411200080598672 > say sin(3) 0.1411200080598672 > $*VM moar (2020.06) > At first perusal one might conclude that calling .sin on an array "auto-joins" the arrays elements, but in fact, calling .sin on an array returns the sin() of the number of array elements. The two calls "@nums.sin" and "@nums.elems.sin" give exactly the same result. I'm ignorant of the 'historically charged' use of the term 'context', although I interpret your comment to suggest that the term 'context' now may be a disfavored concept. If so, then all the more reason to obviate the need to explain this concept to new Raku programmers. --Best, Bill.
Re: Language Design: 'special casing' of split()? (i.e. .split performs concomitant .join? )
Thank you Timo for the favor of a reply! On Sat, Oct 10, 2020 at 3:35 PM Timo Paulssen wrote: > On 10/10/2020 23:21, 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. > > > > 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, 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'. > > Hi Bill, > > the auto-joining of an array is a property of the split method, or more > precisely, a result of split coming from Str. > > Cool has many methods and is in many things. > > You can call .split on Num or Rat, so 0.123451234512345.split("5") would > give you strings, because split stringifies first. > Yes, but if I try to do a similar split() on an array, I end up combining sub-elements of the array. See below where the three element [aXc dXf gXi] becomes the four-element ("a", "c d", "f g", "i").Seq: :~$ #test Timo's code wmichels@bmacbook:~$ raku #enter the REPL To exit type 'exit' or '^D' > dd 0.123451234512345.split("5") ("0.1234", "1234", "1234", "").Seq Nil > dd "0.123451234512345".split("5") ("0.1234", "1234", "1234", "").Seq Nil > my @alpha = "aXc", "dXf", "gXi"; [aXc dXf gXi] > dd @alpha.split("X") ("a", "c d", "f g", "i").Seq Nil > dd @alpha.split("Y") ("aXc dXf gXi",).Seq Nil > Conversely, .join is "a listy cool method" (i just made that up) so what > you call it on will be treated as if it were an array. "hello".join("X") > will pretend you passed ["hello"] and just result in "hello" again. > Yes but...you've given a nice example where a failed join() gives you back the same input. The same thing doesn't happen with split(). Below a failed split() gives you back a joined string (one element): > my @alpha = "aXc", "dXf", "gXi"; [aXc dXf gXi] > say @alpha.elems 3 > dd @alpha.split("Y") ("aXc dXf gXi",).Seq Nil > say @alpha.split("Y").elems 1 Trigonometric methods like sin, cos, tan, are all "numerical cool > methods" so the first thing they do is coerce to Numeric, that's why > "99".tan.say gives you roughly -25.1. > Brian Duggan posted a short "π" array that's very nice; I've expanded it a bit: > my @nums = 0, π/2, 1 * π/2, 2 * π/2, 3 * π/2, 4 * π/2; [0 1.5707963267948966 1.5707963267948966 3.141592653589793 4.71238898038469 6.283185307179586] > dd @nums.sin -0.27941549819892586e0 Nil > > my @ints = 0..9; [0 1 2 3 4 5 6 7 8 9] > dd @ints.log 2.302585092994046e0 Nil > With regards to the @nums array, I input 6 elements and I expected 6 elements back. With regards to the @ints array, I input 10 elements and I expected 10 elements back. You may perceive an impedence-mismatch here, but in my mind, I've created an array for the sole purpose of applying the log function to each element of the array. I didn't use a `$`-sigiled scalar. If I wanted the number of elements of the @ints array, I would have called "@ints.elems". But it seems that Raku believes that I want the log of the length of the @ints array: [ log(10) = approx 2.3025 ], when I really wanted the ten numerics: [-Inf, 0e0, 0.6931471805599453e0, 1.0986122886681098e0, 1.3862943611198906e0, 1.6094379124341003e0, 1.791759469228055e0, 1.9459101490553132e0, 2.0794415416798357e0, 2.1972245773362196e0] Please check out the table near the beginning of this documentation page: > > https://docs.raku.org/type/Cool > > hope that makes things more clear > - Timo > Thanks to you and Tobias for the Docs reference. I certainly tried searching for "split" on https://docs.raku.org/ but ended up reading the page below (and not the more general page on "Cool"): https://docs.raku.org/routine/split Thanks for all your help Timo! --Best, Bill.
Re: Language Design: 'special casing' of split()? (i.e. .split performs concomitant .join? )
On Mon, Oct 12, 2020 at 6:02 AM Brian Duggan wrote: > On Saturday, October 10, William Michels via perl6-users wrote: > > 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. > > This seems pretty convenient and intuitive. At least, it is possible > to mimic that behavior in Raku: > > List.^find_method('split').wrap: { $^a.map: *.split($^b) } > List.^find_method('sin').wrap: *.map: *.sin; > > my @words = ; > my @nums = 0, π/2, 3 * π/2; > > say @words.split(','); > say @nums.sin; > > gives us > > ((a b) (c d)) > (0 1 -1) > > Brian > Thank you for your reply, Brian! user@mbook:~$ #test Brian Duggan code: user@mbook:~$ raku #enter REPL To exit type 'exit' or '^D' > List.^find_method('split').wrap: { $^a.map: *.split($^b) } Routine::WrapHandle.new > List.^find_method('sin').wrap: *.map: *.sin; Routine::WrapHandle.new > my @words = ; [a,b c,d] > my @nums = 0, π/2, 3 * π/2; [0 1.5707963267948966 4.71238898038469] > say @words.elems; 2 > say @words.split('Z').elems; 2 > say @words.split(',').elems; 2 > dd @words.split(','); (("a", "b").Seq, ("c", "d").Seq).Seq Nil > say @nums.elems; 3 > say @nums.sin.elems; 3 > dd @nums.sin; (0e0, 1e0, -1e0).Seq Nil Yes, that works very nicely. There is no longer a difference between splitting on commas vs splitting on whitespace. And I especially like the fact that a failed call to split() no longer joins all array elements into a single string (see examples above and below when attempting to split on 'Z'): > my @words2 = "a b", "c d e"; [a b c d e] > dd @words2 Array @words2 = ["a b", "c d e"] Nil > say @words2.elems; 2 > say @words2.split('Z').elems; 2 > say @words2.split(' ').elems; 2 > dd @words2.split(' '); (("a", "b").Seq, ("c", "d", "e").Seq).Seq Nil Thanks again, Brian! Best, Bill.
Re: Language Design: 'special casing' of split()? (i.e. .split performs concomitant .join? )
Thank you, Joe, for taking the time to write such a cogent reply. And thanks to Tobias and everyone else who has taken the time to reply to my questions. On Sat, Oct 10, 2020 at 3:38 PM Joseph Brenner wrote: > William Michels wrote: > > >I actually wondered where the different programming paradigms > >would be delineated > > I think were the present topic has to do more with the > strong/weak/gradual typing debates-- here Raku is doing an > automatic type conversion that a "strong-typing" fanatic > would sneer at. Though, the way this behavior is implemented > is via the "(almost) everything is an object" philosophy > that Tobias was describing. > > William Michels wrote: > > split() performs an implied join of Array elements > > Yes, that's right, because split is a *string* method, it's as > though you called .Str on the array first. > Playing devil's-advocate here, I don't *know* that split() is a string method. For all I know, there could be a form of split() which splits on bytes, or graphemes, or nulls. I can, for example, split on nulls: split("\0"). Does that properly qualify as a string method? If I call split("\0").WHAT, I'm told I've produced a (Seq), not a string. So when do I *know* that Raku's split() is confined to string substrates? (Substrate is a biochemistry term but I'm sure you get the .gist). What about awk that can apparently split on bytes? Does Raku behave like awk? Or Golang which has a split function that acts on bytes? Does Raku behave like Golang? What about Python that (apparently) can't split on bytes without a prior .decode() step? Is Raku more capable than Python? Or maybe Raku's split() is analogous to Elixir's .slice/x, where a data structure can be "split" into 2 or 3 or x Int parts. Does Raku's split() act like Elixr's .slice? And if Raku's split() acts like Elixr's .slice, who's to say it doesn't act element-wise on each element of an array? https://unix.stackexchange.com/questions/583716/awk-split-each-byte-to-their-own-file-while-specifying-created-filename-to-std https://golang.org/pkg/bytes/ https://stackoverflow.com/questions/13857856/split-byte-string-into-lines https://hexdocs.pm/elixir/1.0.5/String.html What would you *want* to happen when someone treats an array as a > string? > >my @monsters = < blob kong mothera fingfangfoom >; >put @monsters;# blob kong mothera fingfangfoom >say "{ @monsters }"; # blob kong mothera fingfangfoom > Again, I don't know anything about Raku's storage model. Does Raku efficiently pack arrays like PDL (Perl Data Language)? Even if it doesn't, surely the double-quotes and commas are screen-sugar, decorating print calls but otherwise not stored with the object. I might imagine that each element of a Raku array is separated by an ASCII record separator: US (ASCII_31). So when I call Raku's split(), it applies split to each element of the array, and leaves the US record separator (ASCII_31) untouched: https://www.unicode.org/charts/PDF/U.pdf https://www.cisco.com/c/en/us/td/docs/ios/12_4/cfg_fund/command/reference/cfnapph.html# https://www.lammertbies.nl/comm/info/ascii-characters https://ronaldduncan.wordpress.com/2009/10/31/text-file-formats-ascii-delimited-text-not-csv-or-tab-delimited-text/ > What Raku does is a DWIM move: it joins the array on spaces when > you use the array as a string. So these do the same things: > >my $s1 = @monsters.Str; >my $s2 = @monsters.join(" "); >dd( $s1 ); # Str $s1 = "blob kong mothera fingfangfoom" >dd( $s2 ); # Str $s2 = "blob kong mothera fingfangfoom" > > You need to use .join explicitly if you want different behavior: > >my $s3 = @monsters.join(", "); >dd( $s3 ); # Str $s3 = "blob, kong, mothera, fingfangfoom" > > All three of these do the same things: > >my @r1 = @monsters.split("a"); >my @r2 = @monsters.Str.split("a"); >my @r3 = @monsters.join(" ").split("a"); > > The each result in and array like: > > ["blob kong mother", " fingf", "ngfoom"] > Yes, but you've overlooked the obvious test, which is, what happens when I try to split on a character that DOES NOT exist in the array. In that case I end up destroying my array and creating a single element string. So a failed split actually joins (code/results below from the Raku REPL): > say @monsters.Str.split("Z").elems; 1 > dd @monsters.Str.split("Z"); ("blob kong mothera fingfangfoom",).Seq Nil > In this example of yours: > > my @a = "My Bloody Valentine", "Sonic Youth"; > > When you call split on @a, it joins on spaces first (and probably > inadvertantly, throws away the division between 3 elements), > then the actual split operation results in 5 elements: > > @a.split(" ").raku.say; > # ("My", "Bloody", "Valentine", "Sonic", "Youth").Seq > Yes, the call above appears to 'flatten' the array, which isn't what I desired. [ Had I desired to flatten the array, I would probably take a wild guess and call flat(). ]. But I guess that really isn't the end
Re: Language Design: 'special casing' of split()? (i.e. .split performs concomitant .join? )
On Mon, Oct 12, 2020 at 01:14:09PM -0300, Aureliano Guedes wrote: : > This seems pretty convenient and intuitive. At least, it is possible : > to mimic that behavior in Raku: : > : > List.^find_method('split').wrap: { $^a.map: *.split($^b) } : > List.^find_method('sin').wrap: *.map: *.sin; : > : This is like overwrite the function? : Might be better just implement a new function, I mean, a new verb as is : called in R. In Raku these functions already have names, if you count metaoperators as a fancy way to name anonymous functions: say ».split(','); say (0, (π/2, 3 * π/2))».sin; ((a b) (c d)) (0 (1 -1)) As shown by the ».sin example, unary hypers will distribute over multi-dimensional structures for you, just as an APL or R programmer would expect. But that behavior is not intuitively obvious to everyone, so the vector-processing paradigm is not the default. (But we make it really easy to get to when you want it, as you can see. And arguably the explicit presence of » or >> makes your intent clearer to the naïve reader, who at least has something to look up or ask about if they don't understand it.) Larry
Re: Language Design: 'special casing' of split()? (i.e. .split performs concomitant .join? )
These behave like overwriting > List.^find_method('split').wrap: { $^a.map: *.split($^b) } > List.^find_method('sin').wrap: *.map: *.sin; > but they don't have to, since Aureliano started with "wrap" they can be actual wrappers: sub map-over-arg(\A) {my =nextcallee; A.map:{nextone $_}} List.^find_method('sin').wrap: List.^find_method('cos').wrap: my @nums = 0, π/2, 3 * π/2; say @nums.sin; *# (0 1 -1)* say @nums.cos; *# (1 6.123233995736766e-17 -1.8369701987210297e-16)* I'm not sure if that can be simplified to use "nextwith" instead of "nextcallee"–the "map" introduces a new scope which seems to require "nextcallee" The example with "split" is complicated by having 2 positionals only the first of which needs a map, not going to play with that at the moment, left as exercise to interested readers! -y On Mon, Oct 12, 2020 at 9:15 AM Aureliano Guedes wrote: > > > On Mon, Oct 12, 2020 at 10:03 AM Brian Duggan wrote: > >> On Saturday, October 10, William Michels via perl6-users wrote: >> > 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. >> >> This seems pretty convenient and intuitive. At least, it is possible >> to mimic that behavior in Raku: >> >> List.^find_method('split').wrap: { $^a.map: *.split($^b) } >> List.^find_method('sin').wrap: *.map: *.sin; >> > This is like overwrite the function? > Might be better just implement a new function, I mean, a new verb as is > called in R. > > >> my @words = ; >> my @nums = 0, π/2, 3 * π/2; >> >> say @words.split(','); >> say @nums.sin; >> >> gives us >> >> ((a b) (c d)) >> (0 1 -1) >> >> Brian >> > > > -- > Aureliano Guedes > skype: aureliano.guedes > contato: (11) 94292-6110 > whatsapp +5511942926110 >
Re: Language Design: 'special casing' of split()? (i.e. .split performs concomitant .join? )
On Mon, Oct 12, 2020 at 10:03 AM Brian Duggan wrote: > On Saturday, October 10, William Michels via perl6-users wrote: > > 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. > > This seems pretty convenient and intuitive. At least, it is possible > to mimic that behavior in Raku: > > List.^find_method('split').wrap: { $^a.map: *.split($^b) } > List.^find_method('sin').wrap: *.map: *.sin; > This is like overwrite the function? Might be better just implement a new function, I mean, a new verb as is called in R. > my @words = ; > my @nums = 0, π/2, 3 * π/2; > > say @words.split(','); > say @nums.sin; > > gives us > > ((a b) (c d)) > (0 1 -1) > > Brian > -- Aureliano Guedes skype: aureliano.guedes contato: (11) 94292-6110 whatsapp +5511942926110
Re: Language Design: 'special casing' of split()? (i.e. .split performs concomitant .join? )
On Saturday, October 10, William Michels via perl6-users wrote: > 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. This seems pretty convenient and intuitive. At least, it is possible to mimic that behavior in Raku: List.^find_method('split').wrap: { $^a.map: *.split($^b) } List.^find_method('sin').wrap: *.map: *.sin; my @words = ; my @nums = 0, π/2, 3 * π/2; say @words.split(','); say @nums.sin; gives us ((a b) (c d)) (0 1 -1) Brian
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? )
Functions in Raku tend to have one job and one job only. `split` splits a string. So if you call `split` on something that is not a string it gets turned into one if it can. This happens for most functions. Having `split` be the only function that auto-vectorizes against an array would be very confusing. If it isn't the only function, then you have to come up with some list of functions which do vectorize. Then every single person has to memorize that list in its entirety. Which can be difficult even for experts. Perl has a similar list of functions which automatically work on `$_`, and almost no one has that list memorized. Raku very specifically did not copy that idea. --- Raku instead has high level concepts that it uses consistently. One of those concepts is that functions have one job and one job only. So if you call `chars` on anything it gets turned into a string first. On Sat, Oct 10, 2020 at 4:23 PM William Michels via perl6-users < perl6-us...@perl.org> wrote: > So I guess the first question I have is whether the 'auto-joining' of > array elements is specc'ed or not. > > 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, 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'. > > 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 > > x ->.; sin(.) ->.; cos(.) ->.; tan(.) ->.; sqrt(.) > [1] 1.2479614276 0.8867679488 0.8398446968 1.2344525173 0.9431819962 > 0.8044843661 1.1966884594 > [8] 1.0064589934 0.7823305851 1.1415611482 > > library(magrittr) # add a "piping" library: > > x %>% sin %>% cos %>% tan %>% sqrt > [1] 1.2479614276 0.8867679488 0.8398446968 1.2344525173 0.9431819962 > 0.8044843661 1.1966884594 > [8] 1.0064589934 0.7823305851 1.1415611482 > > y <- x %>% sin %>% cos %>% tan %>% sqrt > > is.vector(y) > [1] TRUE > > length(y) > [1] 10 > > > > Now it's true that R has a greatly simplified memory/storage model > compared to Raku. But it's not hard to follow the R-code above, even if you > don't know the language. If at the end of all your function calls you want > to stringify and 'collapse' your 10 element vector into a single element > string, you call paste() on your object, which has a user-definable > 'collapse' argument that defaults to NULL. [For anyone worried about > formatting actual output, R has print() and sprintf() and cat() functions > as well]: > > > length(paste(0:9, y)) > [1] 10 > > paste(0:9, y) > [1] "0 1.24796142755091" "1 0.886767948777031" "2 0.839844696795443" "3 > 1.23445251727454" > [5] "4 0.943181996210625" "5 0.804484366108825" "6 1.19668845937773" "7 > 1.00645899343325" > [9] "8 0.782330585082487" "9 1.14156114815661" > > length(paste(0:9, "=", y, collapse= "; ")) > [1] 1 > > paste(0:9, "=", y, collapse= "; ") > [1] "0 = 1.24796142755091; 1 = 0.886767948777031; 2 = 0.839844696795443; > 3 = 1.23445251727454; 4 = 0.943181996210625; 5 = 0.804484366108825; 6 = > 1.19668845937773; 7 = 1.00645899343325; 8 = 0.782330585082487; 9 = > 1.14156114815661" > > > > When I started learning Perl6/Raku a few years ago I actually wondered > where the different programming paradigms would be delineated. Would > imperative/structural/procedural code be 'closer to the metal' while > functional code would be applied to higher-order data structures like > arrays, arrays-of-lists, arrays-of-hashes, and arrays-of-arrays? And those > higher-order data structures would then be utilized in object-oriented > code, i.e. the programmer would be manipulating classes and class-based > objects of varying complexity to produce a robust and secure program? Or > would Raku implement a different (i.e. better) paradigm hierarchy that I > hadn't anticipated? > > Best Regards, Bill. > > W. Michels, Ph.D. > > > > > > On Tue, Oct 6, 2020 at 1:59 PM Tobias Boege wrote: > >> 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 >> >
Re: Language Design: 'special casing' of split()? (i.e. .split performs concomitant .join? )
William Michels wrote: >I actually wondered where the different programming paradigms >would be delineated I think were the present topic has to do more with the strong/weak/gradual typing debates-- here Raku is doing an automatic type conversion that a "strong-typing" fanatic would sneer at. Though, the way this behavior is implemented is via the "(almost) everything is an object" philosophy that Tobias was describing. Willima Michels wrote: > split() performs an implied join of Array elements Yes, that's right, because split is a *string* method, it's as though you called .Str on the array first. What would you *want* to happen when someone treats an array as a string? my @monsters = < blob kong mothera fingfangfoom >; put @monsters;# blob kong mothera fingfangfoom say "{ @monsters }"; # blob kong mothera fingfangfoom What Raku does is a DWIM move: it joins the array on spaces when you use the array as a string. So these do the same things: my $s1 = @monsters.Str; my $s2 = @monsters.join(" "); dd( $s1 ); # Str $s1 = "blob kong mothera fingfangfoom" dd( $s2 ); # Str $s2 = "blob kong mothera fingfangfoom" You need to use .join explicitly if you want different behavior: my $s3 = @monsters.join(", "); dd( $s3 ); # Str $s3 = "blob, kong, mothera, fingfangfoom" All three of these do the same things: my @r1 = @monsters.split("a"); my @r2 = @monsters.Str.split("a"); my @r3 = @monsters.join(" ").split("a"); The each result in and array like: ["blob kong mother", " fingf", "ngfoom"] In this example of yours: my @a = "My Bloody Valentine", "Sonic Youth"; When you call split on @a, it joins on spaces first (and probably inadvertantly, throws away the division between 3 elements), then the actual split operation results in 5 elements: @a.split(" ").raku.say; # ("My", "Bloody", "Valentine", "Sonic", "Youth").Seq You might play with an explicit join to see what it does: my @r; @r = @a.join("|").split(" "); dd( @r ); # Array @r = ["My", "Bloody", "Valentine|Sonic", "Youth"] Myself, I think I'd be inclined to loop over the elements, e.g. with map: @r = @a.map({ [ .split(" ") ] }); dd(@r); # Array @r = [["My", "Bloody", "Valentine"], ["Sonic", "Youth"]] That's an array of arrays: two top-level elements, each split into 3 and 2 words respectively Note: split does stringification because it's intended to be run on strings, or things that can become strings-- map doesn't do this because it's intended to be run on things like Arrays. This probably is "specced" though not down on the level you're probably thinking of: it's not in the "split" documentation, for example, because it's not really specific to that method. You *could* argue that if you call a string method on an array, that's simply a mistake and it should error out. I think that's what "strong-typing" crowd would say-- they would point out you might have realized faster what was going on in that case. On 10/10/20, William Michels wrote: > So I guess the first question I have is whether the 'auto-joining' of array > elements is specc'ed or not. > > 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, > 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'. > > 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 >> x ->.; sin(.) ->.; cos(.) ->.; tan(.) ->.; sqrt(.) > [1] 1.2479614276 0.8867679488 0.8398446968 1.2344525173 0.9431819962 > 0.8044843661 1.1966884594 > [8] 1.0064589934 0.7823305851 1.1415611482 >> library(magrittr) # add a "piping" library: >> x %>% sin %>% cos %>% tan %>% sqrt > [1] 1.2479614276 0.8867679488 0.8398446968 1.2344525173 0.9431819962 > 0.8044843661 1.1966884594 > [8] 1.0064589934 0.7823305851 1.1415611482 >> y <- x %>% sin %>% cos %>% tan %>% sqrt >> is.vector(y) > [1] TRUE >> length(y) > [1] 10 >> > > Now it's true that R has a greatly simplified memory/storage model compared > to Raku. But it's not hard to follow the R-code above, even if you don't > know the language. If at the end of all your function calls you want to > stringify and 'collapse' your 10 element
Re: Language Design: 'special casing' of split()? (i.e. .split performs concomitant .join? )
On 10/10/2020 23:21, 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. > > 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, 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'. Hi Bill, the auto-joining of an array is a property of the split method, or more precisely, a result of split coming from Str. Cool has many methods and is in many things. You can call .split on Num or Rat, so 0.123451234512345.split("5") would give you strings, because split stringifies first. Conversely, .join is "a listy cool method" (i just made that up) so what you call it on will be treated as if it were an array. "hello".join("X") will pretend you passed ["hello"] and just result in "hello" again. Trigonometric methods like sin, cos, tan, are all "numerical cool methods" so the first thing they do is coerce to Numeric, that's why "99".tan.say gives you roughly -25.1. Please check out the table near the beginning of this documentation page: https://docs.raku.org/type/Cool hope that makes things more clear - Timo
Re: Language Design: 'special casing' of split()? (i.e. .split performs concomitant .join? )
So I guess the first question I have is whether the 'auto-joining' of array elements is specc'ed or not. 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, 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'. 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 > x ->.; sin(.) ->.; cos(.) ->.; tan(.) ->.; sqrt(.) [1] 1.2479614276 0.8867679488 0.8398446968 1.2344525173 0.9431819962 0.8044843661 1.1966884594 [8] 1.0064589934 0.7823305851 1.1415611482 > library(magrittr) # add a "piping" library: > x %>% sin %>% cos %>% tan %>% sqrt [1] 1.2479614276 0.8867679488 0.8398446968 1.2344525173 0.9431819962 0.8044843661 1.1966884594 [8] 1.0064589934 0.7823305851 1.1415611482 > y <- x %>% sin %>% cos %>% tan %>% sqrt > is.vector(y) [1] TRUE > length(y) [1] 10 > Now it's true that R has a greatly simplified memory/storage model compared to Raku. But it's not hard to follow the R-code above, even if you don't know the language. If at the end of all your function calls you want to stringify and 'collapse' your 10 element vector into a single element string, you call paste() on your object, which has a user-definable 'collapse' argument that defaults to NULL. [For anyone worried about formatting actual output, R has print() and sprintf() and cat() functions as well]: > length(paste(0:9, y)) [1] 10 > paste(0:9, y) [1] "0 1.24796142755091" "1 0.886767948777031" "2 0.839844696795443" "3 1.23445251727454" [5] "4 0.943181996210625" "5 0.804484366108825" "6 1.19668845937773" "7 1.00645899343325" [9] "8 0.782330585082487" "9 1.14156114815661" > length(paste(0:9, "=", y, collapse= "; ")) [1] 1 > paste(0:9, "=", y, collapse= "; ") [1] "0 = 1.24796142755091; 1 = 0.886767948777031; 2 = 0.839844696795443; 3 = 1.23445251727454; 4 = 0.943181996210625; 5 = 0.804484366108825; 6 = 1.19668845937773; 7 = 1.00645899343325; 8 = 0.782330585082487; 9 = 1.14156114815661" > When I started learning Perl6/Raku a few years ago I actually wondered where the different programming paradigms would be delineated. Would imperative/structural/procedural code be 'closer to the metal' while functional code would be applied to higher-order data structures like arrays, arrays-of-lists, arrays-of-hashes, and arrays-of-arrays? And those higher-order data structures would then be utilized in object-oriented code, i.e. the programmer would be manipulating classes and class-based objects of varying complexity to produce a robust and secure program? Or would Raku implement a different (i.e. better) paradigm hierarchy that I hadn't anticipated? Best Regards, Bill. W. Michels, Ph.D. On Tue, Oct 6, 2020 at 1:59 PM Tobias Boege wrote: > 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, >
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