This channel is intended for people just starting with the Raku Programming Language (raku.org). Logs are available at irclogs.raku.org/raku-beginner/live.html
Set by lizmat on 8 June 2022.
00:03 ab5tract joined 00:37 ab5tract left 00:43 razetime joined 03:46 razetime left 04:27 razetime joined 05:45 siavash joined 07:38 siavash left 07:40 siavash joined 08:09 dakkar joined 08:14 tea3po left, tea3po joined 08:32 razetime left 08:56 razetime joined 10:24 razetime left
rcmlz Hello, I have a question regarding thread safty of @array.race.map() constructs. I red in the weekly news about this "readable quicksort" implementation demonstrating some Raku features (twitter.com/uzluisf/status/1686785...33417994). While this implementation is very short it unfortunately does not work with the shown test array (as it does not honor dupplicates, e.g. 1 in the test). For fun I 10:29
thougth I could improve that and came up with this: gist.github.com/rcmlz/6cd3afd7043a...c3609e07b4 (runable code with some testcases) multi quicksort(@array) is export { my (@less, @same, @more); my $pivot = @array.roll; @array.race.map(-> $element { given $element cmp $pivot { when Less { @less.push($element) } when More { @more.push($element) }
when Same { @same.push($element) } default { die "$element cmp $pivot failed as total order not defined!" } } }); flat quicksort(@less), @same, quicksort(@more); } My question: is that actually a valid implementation? Especially, is this actually thread-save and is it a good idea to use race.map as I did? Thank you for your thoughts.
10:31 razetime joined 10:34 tankf33der left
nemokosch um, one moment... is it welcome if I bring up another way, something more like an improvement over the original one? 😅 10:38
to be honest, a combination of both (the original one tried to deal with lazy stuff to gain performance, mine wouldn't)
rcmlz yes please, I like to use features like Less/More/Same and Before/After as it allows to show concepts during teaching 10:39
nemokosch oh using Less/More/Same is a good idea for my approach as well 😛
anyway, I suppose the challenge comes from the shared access to @less, @more and @same 10:40
rcmlz yes, this shared access smells fishy to mo - exactly
10:42 teatwo joined
nemokosch stackoverflow.com/questions/437828...en-threads 10:43
the tl;dr seems to be that it might be unsafe - or else .race is useless anyway 10:45
rcmlz So, I am on bottom left - need to rethink then. 10:46
nemokosch bottom right, no?
rcmlz yes, sorry, typo
I also wanted to avoid 3 comparisions, when one actually tells me Less/Same/More 10:47
nemokosch Prime AlexDaniel XD 10:48
cdn.discordapp.com/attachments/768.../image.png
rcmlz when I do the same I tried with grep - as the original idea - I have 3 greps trough the entire array. 10:49
nemokosch the original author used binding so that these are lazy operations
although it would still proceed to process the array twice I guess
so it's rather just some memory micro-optimization 10:50
rcmlz From educational point of view it is nice to stay on simple arrays and use "speaking" operators like "cmp" and results like Less/More etc. 10:52
nemokosch by the way, my opinionated opinion is that you should aim for **@slurpies with the double asterisk
*@slurpies do some magic flattening, frankly it's probably some legacy stuff 10:53
rcmlz Will read what **@slurpies are - never used them so far.
Thank you.
So bottom line: parallel quick sort can not be done the way I tried. Thank you. 10:54
nemokosch m: sub flatty(*@args) { .say for @args }; flatty <a b c>, 'rock', ('and', ), ('roll',);
Raku eval a b c rock and roll
nemokosch versus
m: sub flatty(**@args) { .say for @args }; flatty <a b c>, 'rock', ('and', ), ('roll',);
Raku eval (a b c) rock (and) (roll)
nemokosch @rcmlz back to the quick sort 10:55
what about something like this: 10:56
SmokeMachine m: gist.github.com/FCO/a8d4bf9710faf7...6d790bb5de 11:00
camelia [1 1 2 3 7 8 9]
nemokosch m: multi quicksort([]) { [] } multi quicksort(@values) { my $pivot = @values.head; my %splitted = @values.classify(* cmp $pivot); |quicksort(%splitted{Less}), |%splitted{Same}, |quicksort(%splitted{More}) } say quicksort([7, 2, 1, 8, 1, 9, 3]);
Raku eval Exit code: 1 Cannot resolve caller quicksort(Any:U); none of these signatures matches: (@ ()) (@values) in sub quicksort at main.raku line 5 in sub quicksort at main.raku line 5 in sub quicksort at main.raku line 5 in block <unit> at main.raku line 7
nemokosch okay, so basically what I tried but working 😂 11:01
is default([]) it was, probably
m: multi quicksort([]) { [] } multi quicksort(@values) { my $pivot = @values.head; my %splitted is default([]) = @values.classify(* cmp $pivot); |quicksort(%splitted{Less}), |%splitted{Same}, |quicksort(%splitted{More}) } say quicksort([7, 2, 1, 8, 1, 9, 3]);
Raku eval (1 1 2 3 7 8 9) 11:02
SmokeMachine nemokosch: ☝️
oh! sorry, yes... 11:03
nemokosch another difference is that SmokeMachine used "object hashes" that have typed keys while my hashes simply use string coercion
wrapping the result into an Array is also probably a good idea, for consistency's sake 11:04
rcmlz Cool: @values.classify(* cmp $pivot); 11:05
Thank you SmokeMachine and Nemokosch 11:06
nemokosch there is classify and categorize
classify: it will only go to one part; categorize: it can go to multiple parts at once 11:07
SmokeMachine classify goes multipart too, but in a tree, if I'm not remembering it wrong... and categorize work like tags... 11:08
rcmlz Let me try If I can squeeze in a "race" - that would be than a parallel-two-line-quick-sort
nemokosch yes, it rings a bell for me as well...
I didn't like it though
github.com/Raku/doc/issues/4293 11:09
SmokeMachine m: say ^10 .classify: { ($_ %% 2 ?? "2" !! "!2"), $_ %% 3 ?? "#" !! "!3" } 11:10
camelia {!2 => {!3 => [1 5 7], # => [3 9]}, 2 => {!3 => [2 4 8], # => [0 6]}}
nemokosch and also github.com/Raku/problem-solving/issues/370
SmokeMachine m: say ^10 .categorize: { ($_ %% 2 ?? "2" !! "!2"), $_ %% 3 ?? "#" !! "!3" }
camelia {!2 => [1 3 5 7 9], !3 => [1 2 4 5 7 8], # => [0 3 6 9], 2 => [0 2 4 6 8]}
nemokosch after all, I discovered it when I indeed wanted to classify by a list
SmokeMachine m: say ^10 .classify: { ($_ %% 2 ?? "2" !! "!2"), $_ %% 3 ?? "3" !! "!3" }
camelia {!2 => {!3 => [1 5 7], 3 => [3 9]}, 2 => {!3 => [2 4 8], 3 => [0 6]}}
SmokeMachine m: say ^10 .categorize: { ($_ %% 2 ?? "2" !! "!2"), $_ %% 3 ?? "3" !! "!3" } 11:11
camelia {!2 => [1 3 5 7 9], !3 => [1 2 4 5 7 8], 2 => [0 2 4 6 8], 3 => [0 3 6 9]}
nemokosch what happens if you return nested lists?
m: ^10.classify: { ((2, $ %% 2), (3, $ %% 3)) } andthen .say 11:12
Raku eval ^1 Potential difficulties: Precedence of ^ is looser than method call; please parenthesize at /home/glot/main.raku:1 ------> ^10⏏.classify: { ((2, $_ %% 2), (3, $_ %% 3)
nemokosch oh right, another whitespace hack 🤬
m: ^10 .classify: { ((2, $ %% 2), (3, $ %% 3)) } andthen .say 11:13
Raku eval {(2 False) => {(3 False) => [7]}, (2 False) => {(3 True) => [9]}, (2 False) => {(3 False) => [5]}, (2 False) => {(3 True) => [3]}, (2 False) => {(3 False) => [1]}, (2 True) => {(3 False) => [4]}, (2 True) => {(3 True) => [0]}, (2 True) => {(3 False) => [2]}, (2 True) => {(3 True) => [6]}, (2 True) => {(3 False) => [8]}}
rcmlz So in theory: "@rest.race.classify: * cmp $pivot;" should be faster for large arrays?
nemokosch I don't know if that would be any more thread-safe than your original code 11:14
after all, what can classify be doing? writing a couple of keys in a hash, and a couple of arrays inside it, all this in a deterministic order
rcmlz Yes, true. It would be magic if you can just throw in a race or hyper somewhere and all problems would be solved already 11:16
nemokosch and like you would want the sort to stay stable at least, no? 11:17
that immediately means that the order of elements must be preserved some way
SmokeMachine not it that's creating new arrays like in a reduce (`return [|@agg, $item]`), but I don't think it is...
nemokosch classify creates new arrays but fun fact: it preserves the container of the original value 11:18
at least the way it is implemented now
SmokeMachine I've seen a list of all Seq methods that use race/hyper some years ago... I'm not finding it now to be sure classify does use race/hyper... 11:19
nemokosch in other words, it doesn't copy the classified values, only references them
rcmlz So my final code is now: multi quicksort([]) is export {[]} multi quicksort(@array where @array.elems == 1) is export {@array} multi quicksort(@array) { my $pivot = @array.pick; my %classified is default([]) = @array.classify: * cmp $pivot; flat quicksort(%classified{Less}), %classified{Same}, quicksort(%classified{More}) } That is quite cool ... thank you. 11:28
nemokosch I wonder whether is export is at the right place on a multi candidate
both as in "what would even happen" and as in, you want to export all candidates in this case, right? 11:29
rcmlz I have that in a .rakumod file
11:30 destroycomputers left 11:31 destroycomputers joined
nemokosch hoping for an answer in #raku-irc 11:32
rcmlz Fixed that. Now it reads a bit like the pseudocode. - an empty array is sorted - an array with one lement is sorted - sort an array by picking a pivot and recursively call qicksort on the elements that are less and more than the pivot element. Very nice! Thank you all. 11:41
11:42 razetime left
nemokosch 🍬 11:47
11:47 siavash2 joined 11:48 razetime joined 11:50 siavash left 12:05 tbrowder__ left, tbrowder__ joined 12:36 siavash2 left
SmokeMachine rcmlz: if you have a proto, you can di `is export` only once 12:56
12:56 ab5tract joined
SmokeMachine rcmlz: why `multi quicksort(@array where @array.elems == 1)` instead of `multi quicksort(@array [$])`? 12:59
m: multi a(@b [$]) { say "single one" }; multi a(@b) { say "not single one" }; a []; a [1]; a [1,2]
camelia not single one
single one
not single one
nemokosch that looks rather bizarre from a syntax point of view 13:05
vendethiel Destructuring!
nemokosch a rather implicit version of it 13:06
SmokeMachine another option for my classify version would be: 13:10
m: gist.github.com/FCO/45e87c3cff8747...dd25260043
camelia [1 1 2 3 7 8 9]
SmokeMachine maybe better like this? 13:13
m: gist.github.com/FCO/2853352c510a62...26fd968de3
camelia [1 1 2 3 7 8 9]
SmokeMachine nemokosch: why bizarre? IMHO `@array [$]` is as normal/good as `[$pivot, *@rest]` 13:19
nemokosch the difference is exactly that @array prefix which implicitly describes the same thing. That's what the single space did. 13:20
in this sense it is explicit, after all but I don't think it's a great idea for the space to mean "same thing but described as a pattern" 13:21
SmokeMachine nemokosch: I don't see a better way to show that than the space... Maybe I| got used to it... 13:25
nemokosch especially when in Str $name the single space means something completely different which makes me feel very insecure about the syntax 13:26
in the same context, it meant something else. It's always suspicious that some sort of mangling is going on.
rcmlz My reason for choosing multi quicksort([]) { [] } multi quicksort(@unsorted where @unsorted.elems == 1) { @unsorted } multi quicksort(@unsorted) { ...} and not multi quicksort([]) { [] } multi quicksort(@array [$]) multi quicksort([$pivot, *@rest] is that the former reads more like pseudocode, also for beginners in Raku. Rakus strenght for me is the rich syntax with "speaking" operators etc. - I am not 13:33
focussed to much on short code and hight performance.
SmokeMachine: my (:@Less, :@Same, :@More) := @rest.classify(* cmp $pivot); is even better IMHO from point of readability, as it makes clear that we expect classify() to return 3 arrays 13:38
nemokosch at which point you could really add the colon in front of the parens, which is what is really going on under the hood
(it uses the rules of signatures) 13:39
rcmlz you mean like: my :(@Less, @Same, @More) := @rest.classify(* cmp $pivot); 13:40
SmokeMachine rcmlz: to avoid having title cased variables, you could also do: `my (:Less(@less), :Same(@same), :More(@more)) := @rest.classify(* cmp $pivot);` or `my (:@less, :@same, :@more) := @array.classify: (* cmp $pivot).lc;`
the := inplies the parenthesis before it is a signature... so, `my :(@Less, @Same, @More) := @rest.classify(* cmp $pivot);` and `my (@Less, @Same, @More) := @rest.classify(* cmp $pivot);` should be the same... 13:41
nemokosch yes but conceptually it's always the first thing that happens 13:43
SmokeMachine rcmlz: instead of `multi quicksort(@unsorted where @unsorted.elems == 1) { @unsorted }` it could also be: `multi quicksort([ $single ]) { [ $single ] }` 13:44
nemokosch there is no standalone "list destructuring", it's just a simple case of "signature destructuring" that could be provided as a kind of shortcut
SmokeMachine m: my ($a, $b, @c) = ^5; say [:$a, :$b, :@c] # I considere this a "list destructuring", don't you, nemokosch? 13:47
camelia [a => 0 b => 1 c => [2 3 4]]
nemokosch this is a "list assignment" and a cardinal sin of some sort 13:49
13:50 razetime left
m: my @a = <foo bar>; my @b = <los lobos>; (@a, @b) = (@b, @a); dd @a; dd @b; 13:50
Raku eval Array @a = ((my @Array_6282938576000) = [[], @Array_6282938576000]) Array @b = []
nemokosch don't you know it's the end of the world 🎶
SmokeMachine m: my @a = <foo bar>; my @b = <los lobos>; :(@a, @b) := (@b, @a); dd @a; dd @b; # It seems I was wrong... you do need a "real" signature here... 13:58
camelia Array @b = ["los", "lobos"]
Array @a = ["foo", "bar"]
SmokeMachine m: my @a = <foo bar>; my @b = <los lobos>; (@a, @b) := (@b, @a); dd @a; dd @b; # without it breaks...
camelia ===SORRY!=== Error while compiling <tmp>
Cannot use bind operator with this left-hand side
at <tmp>:1
------> y @b = <los lobos>; (@a, @b) := (@b, @a)⏏; dd @a; dd @b; # without it breaks...
SmokeMachine nemokosch: ☝️ 13:59
*without it, it breaks
nemokosch Yep 14:01
SmokeMachine (now on I'll always add the `:`...) 14:02
14:03 razetime joined
nemokosch This is an offtangent but sometimes what you want is really just assignment, not binding. The bind-swap wouldn't help if you want to retrieve the new value of @vars from a subroutine, for example 14:05
SmokeMachine m: my @a = <foo bar>; my @b = <los lobos>; :(@a, @b) := ([@b], [@a]); dd @a; dd @b 14:15
camelia ["los", "lobos"]
["foo", "bar"]
SmokeMachine m: my @a = <foo bar>; my @b = <los lobos>; :(@a, @b) := ([|@b], [|@a]); dd @a; dd @b
camelia ["los", "lobos"]
["foo", "bar"]
SmokeMachine m: my @a = 1,2,3; dd @a; dd [@a] 14:16
camelia Array @a = [1, 2, 3]
[1, 2, 3]
SmokeMachine does [@] without `,` changes the container? 14:17
m: my @a = 1,2,3; say @a.VAR.WHERE; say [@a].VAR.WHERE
camelia 5193870806680
5193870848360
SmokeMachine m: my $a = 1; dd $a; dd [$a] 14:18
camelia Int $a = 1
[1]
SmokeMachine m: dd [1]
camelia [1]
SmokeMachine m: dd [1,]
camelia [1]
14:41 lizmat_ joined 14:43 lizmat left 14:46 lizmat_ left, lizmat joined
nemokosch [@a] is @a.array iirc 14:54
librasteve m: my @a; say @a.^name; say [@a].^name; 15:27
Raku eval Array Array
librasteve thinking about sort it is kind of the antithesis of hyper ... but I guess that there are map reduce variants of the sort algorithm where you map out and separately sort sub arrays and then have some kind of streaming combiner (maybe with Channels?) that merges the sub arrays in a tree 15:33
oh dang someone has thought of this already en.wikipedia.org/wiki/MapReduce 15:35
nemokosch 😂
15:56 razetime left 16:40 dakkar left 17:31 ab5tract left 20:14 teatwo left 20:15 teatwo joined, ab5tract joined, teatwo left 20:16 teatwo joined 20:21 teatwo left, teatwo joined 20:27 ab5tract left 21:34 ab5tract joined 23:59 guifa__ joined