Что делает duckmap действительно?

Из документации

duckmap будет применять &block к каждому элементу и возвращать новый список с определенными возвращаемыми значениями блока. Для неопределенных возвращаемых значений duckmap попытается спуститься в элемент, если этот элемент реализует Iterable.

Но потом:

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 ведет себя почти так же, как и ожидалось, но я не могу понять, что делает duckmap.

Этот вопрос связан с этой проблемой в perl6/doc. Это можно решить с помощью "Они не могут быть более разными", но я хотел бы найти несколько примеров, когда они делают то же самое, а когда нет, постарайтесь действительно понять, что происходит.

Ответ 1

Утка в duckmap относится к утиной печати; то есть "если он ходит как утка и говорит как утка, это, должно быть, утка".

> say [1,2.2,"3.4",4,"a"].duckmap(-> Str $_ { use fatal; .Int }).perl
[1, 2.2, 3, 4, "a"]

(use fatal так что объект "a".Int failure становится брошенным исключением, так что duckmap улавливает его и возвращает исходные данные)

Это полезно для изменения небольших частей ввода без необходимости особого отношения ко всем возможным входам.

> 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"]

Есть больше различий между duckmap и другими map, но все они есть для этой основной предпосылки.


> [ [<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

(Обратите внимание, что вы не можете делать это вообще с помощью deepmap, поскольку она слишком глубока)
Для того, чтобы получить такое же поведение из map, потребовалось бы гораздо больше работы.

Ответ 2

duckmap уходит вглубь, только если &block не может быть вызван в Array. $_ может быть Array in -> $_ { $_² }.

Пытаться

say $list.duckmap( -> Int $_ {$_²} ); #returns [[1 4 9] [[16 25] 36 49]]

Там duckmap уходит глубоко.