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.
Kaiepi i find it kinda odd because a typecheck on `my` can happen at the container level, but `our` installs a lexical symbol like `my` w/ an extra binding to `OUR` so you can kinda just 00:01
Nemokosch no idea why `ok` vanished but this one works even in the REPL 00:05
also as `raku -e`
01:15 deoac joined, Kaipei left 01:20 razetime joined 01:26 deoac left 03:41 Kaipei joined 03:58 razetime left 04:43 Heptite left 07:58 razetime joined 10:35 Kaipei left 11:25 m_athias left, m_athias joined 12:20 Kaipei joined
<@511826957558611968> dev.to/lizmat/dont-fear-the-grepper-6-4i about laziness, caching and all 12:52
12:55 habere-et-disper joined 12:59 razetime left 13:00 habere-et-disper left
zacque Thanks, that helps! The difference in assigning `Seq` object to a positional or scalar variable is new to me 🤯 13:07
And how the `map` and `grep` can be chained together *lazily* 13:09
Nemokosch A seq object can be assigned to a scalar variable 13:11
and bound to a positional variable
think of that as a different dimension
zacque Just trying it out a little bit, when the Range object is defined to infinity, i.e. `(0..*)`, assigning the `map` result to a positional or scalar is the same
Yup, I can appreciate that 13:12
Nemokosch can you write the code?
zacque Something like: ```raku 13:13
my @myseq = (1..*).map({ say "calculating $_"; $_ + 2});
@myseq.say;
@myseq[0].say;
@myseq[0..10].say;
```
which is different from `my @myseq2 = (1..10).map({ say "calculating $_"; $_ + 2});`, I meant 13:14
So, for a fixed size, assigning to a positional variable is eager by default, but assigning to a scalar variable makes it lazy; for infinite size, both cases are lazy by default? 13:15
Nemokosch uh, moment 13:20
what you are saying sounds reasonable for me but I wouldn't know tbh 13:23
m: my @myseq = (1..*).map({ say "calculating $_"; $_ + 2}); say @myseq[].WHAT; 13:24
because it claims to be an array, I would assume the STORE method handles it in a special way 13:26
somehow it knows that the Seq is infinite, I don't know
13:28 discord-raku-bot left, discord-raku-bot joined
Kaiepi that's all backed by docs.raku.org/type/Iterator#method...until-lazy in this case 13:30
Nemokosch ohh gotcha 13:32
it's not that the infinite version knows that it's infinite
it's that the finite version doesn't consider itself lazy...
m: say (1..10).map({ say "calculating $_"; $_ + 2}).is-lazy 13:33
mind: blown
docs.raku.org/type/Iterator#method_is-lazy 13:34
Superstart033 my $Mind = “blown”
Nemokosch so something that might be lazy, might not _consider itself_ lazy
lol
perhaps is-finite would have been a better name or idk 13:36
or always-lazy
zacque This is confusing... 🤣
Nemokosch technically it's simple
"is-lazy" in fact means "is-always-lazy"
since the infinite version "is always lazy", it won't get pushed 13:37
while the other version is just potentially lazy, and therefore it can (and will) get pushed
zacque Hmm, that doesn't help 13:39
Nemokosch in what regard? 😅
zacque I think in the article, it says `my @result = (1..5).map({ say "calculating $_"; $_ + 2});` is roughly equivalent to ```raku 13:40
my @result;
for (1..5).map({ say "calculating $_"; $_ + 2}) {
@result.push($_);
}
```
But in reality, it's more like ```raku
my @result;
for (1..5).map({ say "calculating $_"; $_ + 2}) {
@result.push-until-lazy($_);
}```?
That's why lazy Seq doesn't produce value
Nemokosch not exactly
push-until-lazy pushes several elements
therefore it replaces the whole "for" 13:41
it's a lower level
``` 13:42
my @result;
(1..5).map({ say "calculating $_"; $_ + 2}).push-until-lazy(@result);
```
I think you could try this
I will, too
oops, needs .iterator
```
my @result;
(1..5).map({ say "calculating $_"; $_ + 2}).iterator.push-until-lazy(@result);
```
fixed, second attempt
<@210313526928080896> do you think this can be further "for-ified", or the low-level Iterator interface would be needed to expand this? 13:45
zacque Hmm, but how about `(1..*).map({ say "calculating $_"; $_ + 2}).iterator.push-until-lazy(@result);` 13:46
Nemokosch yes, same call
zacque I'm trying to see how `push-until-lazy` fits into this picture
Oh?
Nemokosch > The Iterator role implements this method as a no-op if is-lazy returns a True value, or as a synonym of push-all if not.
so in the second case, it does nothing
in the first case, it redirects to .push-all
zacque Ohh, that tells the difference between `my @myseq = (0..*).map({ say "calculating $_"; $_ + 2});` and `my @myseq = (0..10).map({ say "calculating $_"; $_ + 2});` 13:48
Nemokosch yes... it's all because of the different value for .is-lazy
which is a somewhat misleading name
that's why I say you could think of it as is-always-lazy 13:49
zacque Is it? The name seems good to me
Nemokosch docs.raku.org/type/Iterator#method_is-lazy
I mean... `(0..10).map({ say "calculating $_"; $_ + 2})` this is "lazy"
it doesn't calculate anything 13:50
see?
doesn't calculate anything, yet says `False`
zacque Huh? Ok, that's surprising
Nemokosch I think the reason is that iterators are dumb in general 13:51
they don't know much about the underlying content
if they had to figure it out, we would surely lose lazy evaluation
so when in doubt, they rather lie in a humble way, in order to stay _actually_ lazy 13:52
🤣
zacque Hmmm, wait, I'm confused again
Nemokosch tenor.com/view/no-nooo-nooooo-cryi...f-14628566
zacque Then how do you explain the difference in behaviour if both are lazy?
Haha 13:53
Oh nooo
Nemokosch they _are_ both lazy
but they _don't both consider themselves_ lazy
zacque ???
Nemokosch only one of them actually knows about itself that it's lazy
zacque Hmmm... maybe it has something to do with the assignment method?
Nemokosch depends on what "it" is 13:54
zacque Assignment method forces evaluation?
Nemokosch what I said applies regardless the assignment method 13:55
zacque I'm confuse about this statement
Nemokosch why?
zacque Oh...
Nemokosch imagine yourself in the case of a poor iterator 13:57
it can only retrieve one value at once
how can it know if it belongs to lazy data or not? 13:58
basically only if it's told so 13:59
now, when an infinite range is involved, it will be told so
apparently, if the _lazy_ prefix is used, it will again be told so
> my @result = lazy (1..5).map({ say "calculating $_"; $_ + 2}); 14:01
zacque I see
Just now I was also surprised by the fact that `(1..10).map({ say "calculating $_"; $_ + 2}).is-lazy` doesn't print out "calculating ..."
Nemokosch m: my @result = (.map({ say "calculating $_"; $_ + 2}) andthen .is-lazy.say && $_); dd @result;
oops, almost
m: my @result = lazy (1..5).map({ say "calculating $"; $ + 2}) andthen .is-lazy.say && $_; dd @result; 14:03
I'm curious about this
zacque It doesn't print out anything...
Nemokosch so annoying
m: my @result = lazy (1..5).map({ say "calculating $_"; $ + 2}) andthen .is-lazy.say && $_; dd @result;
watch out 14:04
yes! that's it
`my @result = lazy (1..5).map({ say "calculating $_"; $ + 2}) andthen .is-lazy.say && $_; dd @result;` 14:05
no, that's not it...
run it for yourself pls
it says `False` 14:06
and then it proceeds to talk about "lazy list"
yes! 14:07
zacque Ya, false, also, same error for `dd @result`
Nemokosch so `(1..5).map({ say "calculating $_"; $ + 2})` still considers itself not lazy
despite not calculating anything
zacque Oh, the `False` is from evaluating `.is-lazy.say`!
Nemokosch yes
zacque Ok, but this is true 14:09
The conclusion is that the `lazy` effect from the `lazy` keyword comes after assignment?
Nemokosch that's part of the conclusion
zacque Hold on, I need to digest it 14:11
Nemokosch don't assume that I understand all of it 😄 14:21
I think I understand "enough for now", enough to integrate the code into a kind of logic
14:24 discord-raku-bot left, discord-raku-bot joined
zacque Ahhh, so to understand why `say (0..10).map({ say "calculating $_"; $_ + 2}).is-lazy;` doesn't print any "calculating ..." line, you do `my @result = lazy (1..10).map({ say "calculating $_"; $ + 2}) andthen .is-lazy.say && $_;`, which prints `False` 14:30
14:30 razetime joined
It shows that the `Seq` object is sometimes lazy even if `.is-lazy` returns `False` 14:36
So, there is a contradiction. QED. Ha! 14:37
Nemokosch 🤣 14:38
I think the `lazy` prefix "decorates" the value some way
so that it becomes aware of its laziness
without that, it doesn't know about it
zacque But maybe method call is lazy? That's why `(0..10).map({ say "calculating $_"; $_ + 2}).is-lazy.say;` doesn't print any "Calculating ..." line 14:39
So your theory is not quite right? 14:40
Nemokosch with this "black box approach", we can only rely on Occam's razor
the only thing I feel needs "hacking" in my theory is the `lazy` prefix that can somehow let iterables know that they are lazy
on the other hand, I don't think method calls are any special, nor that we need to postulate that 14:41
map returns a Seq, without fetching any values 14:42
in my terms, that sounds enough to call it "lazy"
in the article of lizmat, the terminology is the same 14:44
zacque It seems to me that it only knows after assignment (or maybe after creating the object and "decorating" its value)
So I think assignment does play an important role here
Nemokosch well, let's remove `lazy` and try that way
zacque I see 14:45
Nemokosch try $result and @result as well 14:46
they will both state `False` but only @result will trigger eager evaluation 14:47
_that_ is indeed due to the list assignment
but for the scalar, it will still be lazy and still lie about it 14:48
zacque Huh? You meant comparing these two?
Nemokosch yes
Rog Skimming through this conversation, I would say make sure you’re not observing things that aren’t actually there by using the REPL
Because the REPL will cause stuff to evaluate
Nemokosch I don't think any of this was caused by the REPL 14:49
zacque Both are `False`
Nemokosch yes 14:50
zacque Ah, I see, I'm not aware of that, thanks!
Nemokosch and how are they located compared to the other say's
zacque It's by invoking `raku`
Nemokosch oh okay
add `dd $result` and `dd @result`
after the respective assignments
and remove `lazy` 14:51
I mean, I thought you wanted to investigate the role the assignment plays 14:52
zacque Ah, yes I am
Huh?
Nemokosch with lazy, I think it's almost identical; that's what we have checked, right? 14:53
zacque Ah, yes 14:54
My mind is a mess now haha
Nemokosch I'm trying to "inline" the important points about the process
zacque With separator 14:57
Nemokosch 1. assignments: $ wraps the right handside directly, @ calls STORE (which under the hood calls push-until-lazy - source: Kaiepi :D)
zacque ?
Nemokosch why
zacque What why?
Nemokosch the question mark why
zacque Oh, I mean is this the "answer"? Haha 14:59
Nemokosch meant to continue this
2. `lazy` - it's a statement prefix; might even be weird usage here, I'm not sure what it exactly does here. docs.raku.org/syntax/lazy 15:01
it seems to do "the right thing", whatever that may be exactly
it seems to me that it wraps the right handside into a new Iterable (a Seq in our case) that does know about its laziness 15:03
zacque For lazy vs eager comparison
Nemokosch docs.raku.org/routine/lazy gotcha 15:05
see your last line of output?
it's explicitly marked as lazy
zacque For comparison until infinity 15:08
Not sure why it computes until 101
Yup 15:09
Nemokosch both?
zacque Nope, only for the scalar one
Nemokosch what did the array version produce? 15:11
zacque A lazy list, I commented out the `dd @result` because error `Cannot .elems a lazy list onto a Array` 15:12
Nemokosch I think this is solely related to the presentation of different lazy structures 15:13
by the way "Cannot .elems a lazy list onto a Array" sounds so ungrammatical to me
do you have any idea how this should be read? xD
zacque Think so
Haha! I simply ignore the "onto a Array" part 15:15
Nemokosch so 101 might be an arbitrary number used for gisting
have you seen bisectable6 (the bisect bot) before?
maybe we could check when this phrasing was introduced
xD
zacque Yup, it limits to first 100
Haha, you can git blame on that 15:16
Nope 15:17
Nemokosch okay, wait for it...
if I knew where it was in the code 😉
15:17 Nemokosch joined
only works on the main IRC chat <#633753286209699870> 15:18
zacque github.com/rakudo/rakudo/blob/14fb....pm6#L2534 15:19
Nemokosch gist.github.com/8f8c79094f8124f178...79b3715647 15:20
zacque Oh, interesting 15:21
Looks like a bug to me because the `.message` method is not define 15:23
Nemokosch github.com/rakudo/rakudo/commit/71...aecc4e9c8c welp
the .what value changed
I think it was invented later 15:24
15:24 Nemokosch left
the caption is a bug though, pretty sure 15:25
I think the intention was like "cannot push onto an array" and stuff like that
and `.elems` is miscategorized somehow 15:26
well we pretty much caught a bug 15:30
minor bug but still a bug 😄
I would say this could be our 5 minutes of fame 15:40
but it's not obvious how it should be fixed xD
because the refactor created overlaps in the calls
stuff that used to look different looks identical now
that's why the output changed
zacque Yeahhhhh, we caught a minor bug haha! 15:47
I see 15:48
I'll leave it to the devs lol
Gtg, bye
Nemokosch hahaha 15:49
byez
lizmat FWIW, I explicitly did not want to mention "lazy" in the grepper blog posts 15:54
not until the blog posts about iterators
Nemokosch fair enough 15:59
lizmat: any idea about how the exception message could/should be fixed?
lizmat eh, which one ? 16:00
16:02 razetime left, razetime joined
Nemokosch github.com/rakudo/rakudo/issues/5093 16:09
17:12 razetime left 17:31 Kaipei left 18:19 habere-et-disper joined
habere-et-disper `flat` suggests that it flattens things, but an empty array is flattened into an empty sequence which in turn cannot be flattened. Please can someone illuminate on this Chesterton Fence? 18:27
m: ().flat
camelia ( no output )
habere-et-disper If I turn instead to `slip`, then an empty sequence is still not discarded unless I use the prefix form: 18:28
m: ().Slip
camelia ( no output )
habere-et-disper m: |()
camelia ( no output )
habere-et-disper m: dd ().flat; dd ().Slip; dd |() 18:29
camelia ().Seq
slip()
block <unit>()
19:02 Kaipei joined
Nemokosch Could you provide an example where this behavior has unwanted consequences? 19:22
An empty list is flat by itself, I think so far so good 19:23
habere-et-disper I'm grokking the Exercism Flatten Array exercise 19:24
Yes, I'm with you on the empty list being flat itself. 19:25
19:49 Heptite joined
habere-et-disper Here's my confusion... I don't think I understand what a container is in raku: 20:08
m: m: my $empty-scalar = []; my @empty-array = []; say $empty-scalar.WHAT; say @empty-array.WHAT; say (1, 2, $empty-scalar).flat; say (1, 2, @empty-array).flat;
camelia (Array)
(Array)
(1 2 [])
(1 2)
habere-et-disper Why does the empty array get flattened, but the empty scalar (which holds an empty array) not? Are scalars containers and arrays not? 20:09
20:44 Kaipei left
Nemokosch habere-et-disper: fair enough, it is indeed a bit... complicated 21:07
how to put it 21:11
first, let's clarify that I think this is documented behavior
> Interprets the invocant as a list, flattens non-containerized Iterables into a flat list, and returns that list. Keep in mind Map and Hash types are Iterable and so will be flattened into lists of pairs. 21:12
docs.raku.org/routine/flat 21:13
you might argue that the phrasing is a bit inaccurate because Array IS a container type as well, not only data type
by the way, you didn't retrieve what I think you wanted to retrieve
m: my $empty-scalar = []; my @empty-array = []; say $empty-scalar.VAR.WHAT; say @empty-array.VAR.WHAT; say (1, 2, $empty-scalar).flat; say (1, 2, @empty-array).flat;
now this is the real WHAT 🤣 21:14
m: my $empty-scalar = []; my @empty-array = []; say $empty-scalar.VAR.WHAT; say @empty-array.VAR.WHAT; say (1, 2, $empty-scalar).flat; say (1, 2, @empty-array).flat;
habere-et-disper  m: my $empty-scalar = []; my @empty-array = []; say $empty-scalar.VAR.WHAT; say @empty-array.VAR.WHAT; say (1, 2, $empty-scalar).flat; say (1, 2, @empty-array).flat;
camelia (Scalar)
(Array)
(1 2 [])
(1 2)
21:15
Nemokosch what is going on...
yeah thanks
Scalar is a simple thing; it's what I would just call "variable" in any other language I know 21:16
you can wrap "anything" up into a Scalar 21:17
habere-et-disper So a super-type for lack of a better word. 21:18
Nemokosch it's a type that provides interface for mutation via assignments, and gives an entity to the underlying data 21:19
an Array is not an entity in the sense a Scalar is
you cannot decontainerize it further 21:20
it's structurally not "one thing"
it provides "an interface for mutation via assignments" but that interface is inherently fragmented 21:21
an Array is kind of like a vector/grid of Scalars
the individual elements can be decontainerized from the Scalars - but not the Array itself 21:22
habere-et-disper So the Array is an immutable structure? 21:25
21:26 discord-raku-bot left 21:27 discord-raku-bot joined 21:31 discord-raku-bot left, discord-raku-bot joined
habere-et-disper Thank you for the long explanation! :-) 21:33
I think I might hide until the hyperwhatever makes an appearance:
m: say [1, 2, [3]].flat; say [1, 2, [3]].[**];
camelia (1 2 [3])
HyperWhatever in array index not yet implemented. Sorry.
in block <unit> at <tmp> line 1
Nemokosch 😂 21:35
by the way, is there a reason you have to use arrays in particular?
as opposed to lists 21:36
habere-et-disper No -- just trying to solve the set exercise whose tests have them. 21:37
Nemokosch then I'd say just use lists - they are not a container type, and they do not wrap the items into scalars 21:39
21:39 Kaipei joined
habere-et-disper Thanks! Helpful. :-) 21:45
23:02 habere-et-disper left