problem-solving icon indicating copy to clipboard operation
problem-solving copied to clipboard

HyperWhatever in subscripts

Open gfldex opened this issue 4 years ago • 0 comments

With v6.e we will get SemiLists, both in assiciative and positinal subscribts.

my @a = <1 2 3>;
my %h; %h{||@a} = 42;
say %h;
# OUTOUT: {1 => {2 => {3 => 42}}}

One could say, that the key of a Hash of Hashs or Array of Arrays is a list of keys. This opens the path to implement @array[**], which is NYI right now and %hash{**} which is undefined (and wrongly defaults to %hash{*}.

As it happens, a new beginner was struggling with `%hash.deepmap({ say 'only .value available here'; }). This is not the first and likely no the last time.

A prove of concept implementation in pure Raku (read: sloooow) as follows. https://gist.github.com/gfldex/f2be82aaf19ccaac4245ad35284ac102

use v6.e.PREVIEW;

my %hash := {
    A => {
        B => 1,
        C => 2,
        D => {
            E => 3,
            F => 4,
        },
        G => 5,
        H => 6,
    },
    J => 7,
    K => 8,
};

multi sub postcircumfix:<{ }>( \SELF, HyperWhatever, :$kv!, *%other ) is raw {
    gather for SELF.kv -> $key, $value {
        $value ~~ Associative
        ?? $value.kv.map(&?BLOCK)
        !! take slip $key, $value;
    }
}

multi sub postcircumfix:<{ }>( \SELF, HyperWhatever, :$k!, *%other ) is raw {
    gather for SELF.kv -> $key, $value {
        $value ~~ Associative
        ?? $value.kv.map(&?BLOCK)
        !! take $key;
    }
}

multi sub postcircumfix:<{ }>( \SELF, HyperWhatever, :$v!, *%other ) is raw {
    gather for SELF.kv -> $key, $value {
        $value ~~ Associative
        ?? $value.kv.map(&?BLOCK)
        !! take $value;
    }
}

multi sub postcircumfix:<{ }>( \SELF, HyperWhatever, :$tree!, *%other ) is raw {
    gather for SELF.kv -> $key, $value {
        $value ~~ Associative
        ?? (take slip $key, $value; $value.kv.map(&?BLOCK))
        !! take slip $key, $value;
    }
}

# This requires v6.e .
multi sub postcircumfix:<{ }>( \SELF, HyperWhatever, :$semi!, *%other ) is raw {
    multi sub recurse(%hash) {
        for %hash.kv -> $key, $value {
            recurse $key, $value;
        }
    }
    multi sub recurse($key is copy, Associative $value) {
        for $value.kv -> $child-key, $child-value {
            recurse slip($key, $child-key), $child-value
        }
    }

    multi sub recurse($key, $value) {
        take $key, $value
    }

    gather recurse(SELF);
}

say %hash{**}:kv; # (C 2 H 6 G 5 B 1 E 3 F 4 J 7 K 8)
say %hash{**}:k; # (C H G B E F J K)
say %hash{**}:v; # (2 6 5 1 3 4 7 8)
say %hash{**}:tree; # (A {B => 1, C => 2, D => {E => 3, F => 4}, G => 5, H => 6} C 2 H 6 G 5 B 1 D {E => 3, F => 4} E 3 F 4 J 7 K 8)
say %hash{**}:semi; # (((A C) 2) ((A H) 6) ((A G) 5) ((A B) 1) ((A D E) 3) ((A D F) 4) (J 7) (K 8))
for %hash{**}:semi -> ($deepkey, $value) {
    say [$deepkey.join, %hash{||$deepkey}]; # [J 7]¶[K 8]¶[AG 5]¶[AH 6]¶[AC 2]¶[AB 1]¶[ADF 4]¶[ADE 3]¶
}

# mark is needed to disabiguate from the multi candidate in CORE
multi sub postcircumfix:<[ ]>( \SELF, HyperWhatever:D, :$mark! ) is raw {
    gather SELF.deepmap(*.take)
}

multi sub postcircumfix:<[ ]>( \SELF, HyperWhatever:D, :$semi! ) is raw {
    multi sub recurse(@array) {
        for @array.kv -> $key, $value {
            recurse $key, $value;
        }
    }
    multi sub recurse($key is copy, Positional $value) {
        for $value.kv -> $child-key, $child-value {
            recurse slip($key, $child-key), $child-value
        }
    }

    multi sub recurse($key, $value) {
        take $key, $value
    }

    gather recurse(SELF);

}

my @array := [1, [2, [3]], 4, [5, 6]];
say @array[**]:mark; # (1 2 3 4 5 6)
for @array[**]:semi -> ($deepkey, $value) {
    say $deepkey, ' -> ', @array[||$deepkey]; # 0 -> 1¶(1 0) -> 2¶(1 1 0) -> 3¶2 -> 4¶(3 0) -> 5¶(3 1) -> 6¶
}

Adding this as a module is hindered by the NYI candidate of @array[**] in CORE.

This proposal would remove a long standing NYI and allows iteration over LoL and HoH with ease.

It may be wise to think about a .deepmap({ say .key, .value;}, :kv) candidate to allow functional iteration.

gfldex avatar Jun 29 '21 18:06 gfldex