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:44
archenoth left
01:17
frost joined
01:46
chikega joined
|
|||
chikega | Hi everyone, are there any video tutorials about learning the Raku language? | 01:47 | |
01:51
chikega left
02:46
jetchisel left
02:49
jetchisel joined
03:06
MasterDuke left
03:09
razetime joined
03:27
razetime left
04:06
razetime joined
08:03
razetime left
08:20
razetime joined
08:34
frost left
|
|||
lizmat | there are: www.youtube.com/results?search_que...23rakulang is a good starting point ? | 08:44 | |
09:00
crystalfrost[m] left
|
|||
Nemokosch | Do you think a tematic Raku series would help? I used to love making tutorial series | 09:00 | |
09:00
crystalfrost[m] joined,
crystalfrost[m] left
|
|||
lizmat | I think it would, if you feel up to it :) | 09:04 | |
Nemokosch | The main question is if I should try to aim for a "first language" approach or an "nth language" assumption will do | 09:06 | |
lizmat | fwiw, personally I would love to see a "first language" approach, because there are quite a few tutorials already coming from other languages | 09:07 | |
09:31
razetime left,
razetime_ joined
|
|||
zacque | Why is my `@pascal` has different values from calling the `pascal-sequence` directly? paste.debian.net/1255512/ | 09:41 | |
What's going on with the assignment? | |||
gfldex | <@511826957558611968> you don't reset @k and the result-array @pascal contains referenced to @k. So the last change to @k will end up x times in @pascal. | 09:46 | |
m:``` | 09:50 | ||
sub pascal-sequence(Int:D $number) { | |||
my @k; | |||
gather { | |||
for 1..$number { | |||
@k = 1, | @k >>+>> (| @k[1..*], 0); | |||
take @k.clone; | |||
} | |||
} | |||
} | |||
sub MAIN(Int:D $rows where $rows >= 3) { | |||
my @pascal = (pascal-sequence $rows); | |||
say @pascal; # OUTPUT: [[1 4 6 4 1] [1 4 6 4 1] [1 4 6 4 1] [1 4 6 4 1] [1 4 6 4 1]] | |||
say (pascal-sequence $rows); # OUTPUT: ([1] [1 1] [1 2 1] [1 3 3 1] [1 4 6 4 1]) | |||
} | |||
MAIN(5); | |||
``` | |||
m:``` | |||
sub pascal-sequence(Int:D $number) { | |||
my @k; | |||
gather { | |||
for 1..$number { | |||
@k = 1, | @k >>+>> (| @k[1..*], 0); | |||
take @k.clone; | |||
} | 09:51 | ||
} | |||
} | |||
sub AIN(Int:D $rows where $rows >= 3) { | |||
my @pascal = (pascal-sequence $rows); | |||
say @pascal; # OUTPUT: [[1 4 6 4 1] [1 4 6 4 1] [1 4 6 4 1] [1 4 6 4 1] [1 4 6 4 1]] | |||
say (pascal-sequence $rows); # OUTPUT: ([1] [1 1] [1 2 1] [1 3 3 1] [1 4 6 4 1]) | |||
} | |||
AIN(5); | |||
``` | |||
I got the feeling that there is a sequence operator waiting to be used for this problem. :) | 09:52 | ||
zacque | Hmm, I don't get it, but `say (pascal-sequence $rows);` does give the correct result? | 09:53 | |
I hope it does! 😄 | 09:54 | ||
Nemokosch | it is seriously weird that one works and the other doesn't | ||
but what you are doing was clearly a bad idea | 09:55 | ||
ie modifying it in-place and taking it multiple times | 09:56 | ||
actually, I have an idea why it's so weird | |||
@vars are eager by default | |||
so it fetched your whole sequence, and the inner list reached the last element | |||
so you got the last element multiple times | |||
on the other hand, the sequence was lazy so the mutation happened on the fly, giving the correct results | |||
if my hypothesis is correct, it would work correctly with ` my @pascal = lazy (pascal-sequence $rows);` | 09:57 | ||
zacque | Ok, so `take` always return a reference to the variable? | 10:16 | |
I don't see how lazy and eager play a role here, because it doesn't say that `gather/take` is always lazy | 10:17 | ||
Putting `lazy` in front of `pascal-sequence` doesn't help either | 10:18 | ||
Nemokosch | pretty much everything is always lazy | ||
it would be easier to collect the counterexamples | |||
zacque | Oh, that's new to me. But I don't see it stated in the docs =X | 10:19 | |
Hmmm, I mean why do you say that everything is always lazy? | 10:21 | ||
Nemokosch | ~~because it's quite accurate~~ | ||
it's a general design principle that everything that can return Seq over List, will return Seq over List | |||
X, Z, map, grep, in fact gather and take is rather obvious in this list | |||
because it's like the Raku version of generators and generators are lazy by concept | 10:23 | ||
zacque | Huh? But Seq is only potentially lazy, from the doc "class Seq: An iterable, potentially lazy sequence of values" | ||
I guess it meant that some functions taking Seq should be able to handle lazy list? | |||
Nemokosch | I'd say there is no big difference between "lazy" and "potentially lazy" | 10:24 | |
the implications come with the potential | 10:25 | ||
it's rather a semantic argument, if we mean "lazy" as implementation or "lazy" as interface | |||
"potentially lazy" is about the interface | |||
zacque | I don't think it matters if that's an implementation detail | ||
Nemokosch | you shall not assume that it's not lazy | ||
zacque | From the user perspective, I guess I can safely assume all are not lazy unless declared otherwise? | ||
Nemokosch | it's rather the opposite | 10:27 | |
zacque | I meant if I work with the built-in lists and operators | ||
Nemokosch | yeah no | ||
almost everything is "potentially lazy", unless you ask otherwise | |||
zacque | Hmmm, okay, I'll keep it in mind while learning more about Raku | ||
Thanks | |||
Nemokosch | this is really good when working with loads (potentially infinite) of data | ||
zacque | But in the case, I think the laziness doesn't matter? Cause I've put `lazy` keyword and it gives the same result | 10:28 | |
Yup, agree | 10:29 | ||
Nemokosch | for me it didn't | ||
zacque | Huh? Can you elaborate further? You've got a different result with `lazy`? | ||
gfldex | m:``` | ||
my \pascal = (1,), (1,1), -> @a { 1, |(@a «+» (|@a[1..*], 0)) } … *; | |||
say pascal[^10]; | |||
``` | |||
Nemokosch | yep | 10:30 | |
I did this | 10:31 | ||
zacque | Ah, I see. Thanks for showing your code | ||
Mine still not working even with `lazy`. paste.debian.net/1255516/ | |||
Guess I should use your approach | 10:32 | ||
Nemokosch | [^4] seems to be too eager | 10:33 | |
zacque | I think it works with `@pascal` as well, is there a specific reason that you use `\pascal`? | ||
What do you mean? | |||
Nemokosch | tbh I don't know how to properly use this lazy mess but if you iterate it, you can see the results popping out one after the other | 10:34 | |
I replaced your @pascal[^4] line to | 10:35 | ||
```perl | |||
.say for @pascal; | |||
``` | |||
and then the right results were indeed popping out | |||
zacque | Yes indeed, together with the `lazy` keyword | 10:37 | |
Nemokosch | yep | ||
docs.raku.org/language/list#index-...le_objects I'm reading this rn | |||
zacque | Hmmm, that's so confusing right now | 10:38 | |
I don't think it helps? | 10:39 | ||
Nemokosch | not detailed enough... | ||
right | |||
There is one thing I feel we need to know | |||
zacque | What's it? | ||
Nemokosch | are the elements of the lazy list still the very same element multiple times, or not | ||
because if they are, it's inevitable that once we fetch more at once, it will always have the same value | 10:40 | ||
zacque | I guess it is the same variable? If not, it won't be lazy 😂 | 10:41 | |
gfldex | `lazy` sneaks another `Seq` in that decontainerises the values in `@k`. When assigned to the Array, fresh containers are being filled with values. | ||
Nemokosch | <@511826957558611968> | ||
```perl | 10:42 | ||
my @pascal = lazy (pascal-sequence $rows); | |||
say @pascal[0]; | |||
say @pascal[0].WHERE; | |||
say @pascal[1]; | |||
say @pascal[1].WHERE; | |||
say (pascal-sequence $rows); # OUTPUT: ([1] [1 1] [1 2 1] [1 3 3 1] [1 4 6 4 1]) | |||
``` | |||
so yes | |||
it's the very same variable retrieved in multiple states | 10:43 | ||
okay, now, this makes it fairly obvious why retrieving a part of the list will contain the same value | |||
as gfldex pointed out with his very first code example (calling .clone), your array doesn't have copies | 10:44 | ||
it has the same variable over and over | |||
zacque | Can I know why does it matter? | 10:45 | |
This is a bit over my head right now | |||
I see, didn't know about `WHERE` before this | |||
Let me see what if without the `lazy` keyword? | |||
Nemokosch | it will be the same pretty sure, except the values will match | 10:46 | |
gfldex | `return @k` doesn't return the values in `@k` but `@k` itself. You keep overwriting the values in `@k`, so you end up with the values of the very last overwriting. | 10:47 | |
Nemokosch | okay, thankfully we are saying the same thing with different words | ||
zacque | Okay, I see, I've tried it out myself | ||
Nemokosch | so you don't have to understand two things at once but one thing twice 😄 | ||
zacque | Okay, so `take @k` here behaves similarly to `return @k`? | 10:48 | |
Does it apply to all container variables? Or is it a special case? | 10:49 | ||
So, when I'm passing a `@var` around, I'm passing the reference around? | |||
Kaiepi | `take` behaves like `return` wrt containers | ||
Nemokosch | From what I know, something that has an Array _container_ (like @-sigilled vars by default), cannot just drop that container | 10:50 | |
gfldex | `take @k[]:v;` works too and might be faster as a `.clone`. The zen slice with `:v` also removes any holes. | ||
Nemokosch | I noticed a gotcha | 10:52 | |
m: my @k = <blah foo bar>; @k =:= @k[]:v andthen .say; | |||
weird parsing as I clearly meant (@k[]:v) | |||
my @k = <blah foo bar>; @k =:= (@k[]:v) andthen .say; | 10:53 | ||
<@511826957558611968> =:= will be useful, trust me | 10:54 | ||
it's the container equivalence | |||
zacque | I'll pass `:v` for now, thanks you for your time and effort 😄 | ||
It looks weird... 😄 | |||
Nemokosch | ie "are these two things the same one thing" | ||
m: my @k = <blah foo bar>; @k =:= (@k[]:v) andthen .say; | |||
no, they aren't - thank heavens, in this case | |||
zacque | Ah, it's the container identity operator, so it checks whether two "references" are equal | 10:56 | |
Nemokosch | yes, basically | ||
zacque | I don't think it helps in this case either | ||
But glad to learn about it | |||
Nemokosch | it helps to know if you have the "same variable" over and over | ||
let me take your original code again | |||
zacque | How is `=:=` different from `===` wrt container? Some experiment shows that they are the same? See: | 10:58 | |
```raku | |||
[0] > (1,2,3) =:= (1,2,3) | |||
False | |||
[1] > (1,2,3) === (1,2,3) | |||
False | |||
[2] > my @foo = (1,2,3); | |||
[1 2 3] | |||
[3] > @foo =:= @foo | |||
True | |||
[4] > @foo === @foo | |||
True | |||
[5] > @foo === (1,2,3) | |||
False | |||
``` | |||
Nemokosch | the difference is that === says true if you drop the container on one side | 10:59 | |
while =:= would say false to that | 11:00 | ||
zacque | Erm, is there an example for that? I don't know how to "drop the container" | ||
Nemokosch | in fact, I suspect === always drops the container | ||
yes, your code is a perfect example | |||
```perl | |||
sub MAIN(Int:D $rows where $rows >= 3) { | |||
my @pascal = (pascal-sequence $rows); | |||
say [===] @pascal; | |||
say @pascal[^$rows]; # OUTPUT: [[1 4 6 4 1] [1 4 6 4 1] [1 4 6 4 1] [1 4 6 4 1] [1 4 6 4 1]] | |||
say (pascal-sequence $rows); # OUTPUT: ([1] [1 1] [1 2 1] [1 3 3 1] [1 4 6 4 1]) | |||
} | |||
``` | |||
it will say True | |||
I wish I could phrase what happened here xD | 11:02 | ||
zacque | It's okay! I know about `[]`! | ||
It's the `reduce` operator | |||
Nemokosch | that helps | ||
but there is more... | |||
so @pascal wraps the same Array container into different Scalar containers | |||
zacque | So, it shows that every element are in fact the same container | ||
Nemokosch | if you assign to @pascal[0], that won't be reflected in @pascal[1] | ||
because they are put into different Scalar containers | |||
you can even try that | |||
zacque | I don't follow here... | 11:03 | |
Nemokosch | I mean, understandable, I've been spending more than one year | 11:04 | |
zacque | What's the deal with Scalar containers? | ||
Nemokosch | to kinda sorta understand variables | ||
zacque | Ah, scalar container is a catch indeed | ||
Nemokosch | let's wait for Kaiepi | ||
zacque | The doc says it won't get flatten | ||
But, but, but they have the same value?? | 11:06 | ||
🤦♂️ | |||
Nemokosch | it's like the containers are nested | ||
there is an item of the array, and that item contains an array | |||
the items don't match, the underlying arrays do match | |||
zacque | Ya, I get this, `pascal-sequence` returns a (lazy?) array of list | ||
Nemokosch | =:= will say false for the items | ||
=== will say true because it drops the scalar container and finds the array | 11:07 | ||
zacque | Then when I assign `pascal-sequence` to `@pascal` it will be coerced to `array` type | 11:08 | |
Kaiepi | `my @pascal = ...` makes an empty `Array`, then assigns to fresh `Scalar` containers within this for each element in `pascal-sequence`'s `gather` (`Seq`) | ||
it does this eagerly because the `gather` isn't `lazy` | |||
if you assign an array, it copies from the containers within that | |||
zacque | Okay, so an array assignment to an array performs an implicit iteration? Makes sense... | 11:10 | |
Nemokosch | array assignment calls .STORE | ||
zacque | If eager I meant | ||
Nemokosch | by definition | ||
Kaiepi | neat thing is if you assign a lazy iterable to an array, consume some values, then assign that to another array, it preserves any laziness left | ||
zacque | But the state remains right? Make sense... | ||
I meant it'll follow from last "consumption" | 11:11 | ||
Kaiepi | yeah | ||
zacque | But I still don't get the "different Scalar containers" part | ||
Nemokosch | I'm describing it, hold on | 11:12 | |
zacque | Ok, thanks | ||
Nemokosch | pls <@210313526928080896> also hold on in case I mess something up big time 😅 | ||
Kaiepi | ok 😛 | ||
zacque | Please take your time! Gtg, I'll be right back in about an hour... | 11:13 | |
Nemokosch | 1. `my @pascal = ...` this is an "array assignment, hence calling STORE with the content on the right handside | 11:14 | |
2. because the rhs wasn't explicitly marked lazy, the content is traversed eagerly | |||
3. the content is some Iterable that consists of the very same Array container over and over again (let me call this `gathered` | |||
4. STORE allocates Scalar containers, the elements of the @pascal array | |||
5. as it traverses `gathered`, it puts the elements of it (which are the same Array container over and over) into the Scalar containers | |||
1. `my @pascal = ...` this is an "array assignment, hence calling STORE with the content on the right handside | |||
2. because the rhs wasn't explicitly marked lazy, the content is traversed eagerly | |||
3. the content is some Iterable that consists of the very same Array container over and over again (let me call this `gathered`) | |||
4. STORE allocates Scalar containers, the elements of the @pascal array | |||
5. as it traverses `gathered`, it puts the elements of it (which are the same Array container over and over) into the Scalar containers | |||
so you end up with | 11:15 | ||
@pascal - an Array container on top | |||
the elements of @pascal - Scalar containers that you can mutate | |||
the current contaent of the elements - the same one Array container (for all elements) | |||
so you end up with | |||
@pascal - an Array container on top | |||
the elements of @pascal - Scalar containers that you can mutate | |||
the current content of the elements - the same one Array container (for all elements) | |||
Kaiepi | pretty much | 11:18 | |
repeated `STORE`s clobber any existing containers within the array, but the wrapper remains | |||
Nemokosch | also, from what I understand (and iirc lizmat told me this), Arrays can not be decontainerized | 11:21 | |
Kaiepi | the `Array` is the container and the value | ||
Nemokosch | they are like bundled | ||
a mnemonic/mental aid to it: Scalars do have one identity while Arrays are inherently divided into pieces | 11:25 | ||
I always imagine something like this for an array: | |||
(array as in the container) | |||
lizmat | note you *can* put an Array into a container | 11:26 | |
but it will be considered a single object like any other object in a container | |||
m: my $a = [1,2,3]; .say for $a | |||
camelia | [1 2 3] | ||
Nemokosch | a grid is made a grid by its cells, it's not a thing on its own | 11:27 | |
- unless, of course, you put the whole thing into a Scalar container 😄 | |||
okay, you were faster 😛 | |||
lizmat | :-) | ||
Nemokosch | the more time you spend with it, the more logically sound it becomes | 11:29 | |
but a thorough demostration of it is still on my wanted list | 11:31 | ||
yes, I know that article and it did help | |||
but still, "more more more" | |||
zacque | Hang on, let me digest your messages 😄 | 12:15 | |
Okay, so without `lazy`, the RHS (`gathered`) is evaluated eagerly by calling `STORE` on it. `STORE` constructs an `Array` of `Scalar` elements. In this case, the `Scalar` elements are actually `Array` elements (containing other `Scalar` elements), so the result is an `Array` of `Scalar` `Array` of `Scalar` something. Finally, this result is assigned to the variable `@pascal`. | 12:29 | ||
Ermm, so each of the `Scalar` elements in an `Array` has unique identity? That's why you said it's "different Scalar containers" | 12:31 | ||
Nemokosch | I think you are on the right track | ||
zacque | So, that why I got this: ```raku | ||
sub MAIN(Int:D $rows where $rows >= 3) { | |||
my @pascal = (pascal-sequence $rows); | |||
say [===] @pascal; # Output: True | |||
say [=:=] @pascal; # Output: False | |||
} | 12:32 | ||
``` | |||
12:55
saint- joined
13:36
razetime_ left
13:50
razetime joined
14:54
jgaz joined
17:00
razetime left
19:24
jgaz left
20:54
sivoais left,
sivoais joined
22:16
MasterDuke joined
|