From the documentation
duckmap
will apply&block
on each element and return a new list with defined return values of the block. For undefined return values,duckmap
will try to descend into the element if that element implementsIterable
.
But then:
my $list = [[1,2,3],[[4,5],6,7]];
say $list.deepmap( *² ); # [[1 4 9] [[16 25] 36 49]]
say $list.duckmap( *² ); # [9 9]
deepmap behaves pretty much as expected, but I can't really make any sense of what duckmap
is doing.
This question is related to this issue in perl6/doc. It can be solved with "They couldn't be more different", but I would like to find some examples where they do the same, and when they don't, try and understand really what's going on.
The duck in duckmap
refers to duck-typing; that is “if it walks like a duck and talks like a duck, it must be a duck.”
> say [1,2.2,"3.4",4,"a"].duckmap(-> Str $_ { use fatal; .Int }).perl
[1, 2.2, 3, 4, "a"]
(use fatal
is there so that the "a".Int
failure object becomes a thrown exception, so that duckmap
catches it and returns the original data instead)
This is useful for changing small portions of the input without having to specially deal with every possible input.
> say [1,2.2,"3.4",4,"a"].map(-> $_ { $_ ~~ Str ?? .Int // .self !! .self }).perl
[1, 2.2, 3, 4, "a"]
> say [1,2.2,"3.4",4,"a"].deepmap(-> $_ { $_ ~~ Str ?? .Int // .self !! .self }).perl
[1, 2.2, 3, 4, "a"]
There are more differences between duckmap
and the other map
s, but they all are there for this basic premise.
> [ [<a b c>], [1,2,3], [[4,5,6],] ].duckmap(-> @_ where .all ~~ Int { @_.Str } ).perl
[["a", "b", "c"], "1 2 3", ["4 5 6"]]
> [ [<a b c>], [1,2,3], [[4,5,6],] ].map(-> @_ { @_.all ~~ Int ?? @_.Str !! @_.self } ).Array.perl
[["a", "b", "c"], "1 2 3", [[4, 5, 6],]] # doesn't match, as map is one level deep
(Note that you can't do the above at all with deepmap
, as it goes too deep)
In order to get the same behaviour out of map
, would require potentially much more work.
duckmap
goes deep only if &block
can not be called on Array.
$_
can be Array in -> $_ { $_² }
.
Try
say $list.duckmap( -> Int $_ {$_²} ); #returns [[1 4 9] [[16 25] 36 49]]
There, duckmap
goes deep.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With