{ my ( $test, $modify ); sub walk { my $ref; ( $test, $modify, $ref ) = @_; ref $modify eq 'CODE' and ref $test eq 'CODE' or croak 'First 2 arguments must be coderefs'; return _walk($ref); } sub _walk { my ( $ref ) = @_; return $modify->($ref) if $test->($ref); given ( ref $ref ) { when ( '' ) { return $ref; } when ( 'ARRAY' ) { return map { _walk($_) } @$ref; } when ( 'HASH' ) { return map { $_ => _walk($ref->{$_}) } keys %$ref; } default { carp "I'm confused by $ref" } } } }