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
|