Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Raku Next Steps: Hyperactive Metang

Raku Next Steps: Hyperactive Metang

(Need to catch up? See the "Raku for Beginners class from 2023 at: https://youtu.be/eb-j1rxs7sc and https://youtu.be/2UO-LEhOkiM )
Time to start thinking in Raku!
Have you:
* Written nested loops?
* Summed a list, or created a running total?
* Compared elements of one array to another array, or to the same array?
Raku's meta-operators do these (and much more) so concisely that it can change your thinking.
Come let me "wow" you!
You are likely doing reduction, production, Cartesian cross-product, combinations, and zipping, even if you don't think in those terms.In Raku, we have concise ways to express these tasks!

Yay!

...with operators so tight that they can change the way you think about your problem-solving!

Hooray! Large cheer!

...and often with two or three hard-to-distinguish ways to do it!

Woohoo!
Wait, what???

TIMTOWTDI, come find out when to use which way!

Presenting hyper-operators and meta-operators in a way that will move us from typical reactions of "Oh! Cool!" to actual adoption in everyday coding, by focusing on spotting the use-cases. For example, "When you see FOO, think BAR", where FOO might be nested loops walking the full span of the same array twice, and BAR would be the `X` operator.

Bruce Gray

June 27, 2024
Tweet

More Decks by Bruce Gray

Other Decks in Programming

Transcript

  1. Raku Next Steps: Hyperactive Metang ( Starting to think in

    Raku )
 
 { with Meta-Operators like Z,X,Reduce,Hyper } [ Part 1 of a "Intermediate Raku" class ] <ABRIDGED> The Perl and Raku Conference
 
 2024-06-27
  2. 10 • https://glot.io/new/raku for online coding
 • Mac: brew install

    rakudo-star • Windows/Linux: https://rakudo.org/downloads • Docker: • REPL on any system: • docker run --rm -it rakudo-star • Script on Mac or Unix: • docker run --rm -v "$(pwd):/script" rakudo-star raku /script/a.raku • Script on Windows: • docker run --rm -v "%cd%:/script" rakudo-star raku /script/a.raku Run online, or install locally
  3. Plan9! • Operator review • Meta-ops: • reduce • produce

    • zip • cross • hyper/race • the good, the bad, and the beautiful
  4. Different meanings by position In Perl: / Division: if ($x

    / 3 > 5) {…} Regex start: if ($x =~ /abc/) {…} 17
  5. Different meanings by position say 15 < 17 && 17

    > 16; say < Alice Bob Carol David >; 18
  6. Different meanings by position say 15 < 17 && 17

    > 16; say <Alice Bob Carol David>; 19
  7. ASCII upgrades, Unicode Fallbacks « << » >> ≠ !=

    ≤ <= ≥ >= ∈ (elem) ∋ (cont) 20
  8. +-*/ Math ~ String && || Logical ! + ?

    Coercion & | Junction ∪ ∩ ∈ Set .. ^..^ Range , List := Binding !!! Stub 27
  9. In fi x, Pre fi x, Post fi x Operators

    say 5 ** 2; # power(5, 2) say 2 + 2; # add(2, 2) say +( '9' ~ '9' ); # make_numeric( # concat('9','9') # ) $z++; # $z = add($z, 1) 31
  10. Perl, C, so many others… $foo = $foo + 5;

    $foo += 5; # op= $foo >>= 1; 35
  11. Perl, C, so many others… $foo = $foo + 5;

    $foo += 5; # op= $foo >>= 1; $foo max= 7; 36
  12. Perl, C, so many others… $foo = $foo + 5;

    $foo += 5; # op= $foo >>= 1; $foo max= 7; $foo = $foo yourop $bar; $foo yourop= $bar; 37
  13. sub sum (@ns) { | sub product (@ns) { |

    sub join (@ss) { my $total = 0; | my $prod = 1; | my $ret = ''; for @ns -> $n { | for @ns -> $n { | for @ss -> $s {. $total += $n; | $prod *= $n; | $ret ~= $s; } | } | } return $total; | return $prod; | return $ret; } | } | } 39
  14. sub sum (@ns) { | sub product (@ns) { |

    sub join (@ss) { my $total = 0; | my $prod = 1; | my $ret = ''; for @ns -> $n { | for @ns -> $n { | for @ss -> $s {. $total += $n; | $prod *= $n; | $ret ~= $s; } | } | } return $total; | return $prod; | return $ret; } | } | } 40
  15. sub sum (@ns) { | sub product (@ns) { |

    sub join (@ss) { my $total = 0; | my $prod = 1; | my $ret = ''; for @ns -> $n { | for @ns -> $n { | for @ss -> $s {. $total += $n; | $prod *= $n; | $ret ~= $s; } | } | } return $total; | return $prod; | return $ret; } | } | } 41
  16. sub sum (@ns) { | sub product (@ns) { |

    sub join (@ss) { my $acc = 0; | my $acc = 1; | my $acc = ''; for @ns -> $n { | for @ns -> $n { | for @ss -> $s {. $acc += $n; | $acc *= $n; | $acc ~= $s; } | } | } return $acc; | return $acc; | return $acc; } | } | } 42
  17. sub sum (@ns) { | sub product (@ns) { |

    sub join (@ss) { my $acc = 0; | my $acc = 1; | my $acc = ''; for @ns { | for @ns { | for @ss { . $acc += $_; | $acc *= $_; | $acc ~= $_; } | } | } return $acc; | return $acc; | return $acc; } | } | } 43
  18. sub sum (@x) { | sub product (@x) { |

    sub join (@x) { my $acc = 0; | my $acc = 1; | my $acc = ''; for @x { | for @x { | for @x { . $acc += $_; | $acc *= $_; | $acc ~= $_; } | } | } return $acc; | return $acc; | return $acc; } | } | } 44
  19. sub sum (@x) { | sub product (@x) { |

    sub join (@x) { my $a = 0; | my $a = 1; | my $a = ''; for @x { | for @x { | for @x { . $a += $_; | $a *= $_; | $a ~= $_; } | } | } return $a; | return $a; | return $a; } | } | } 45
  20. sub sum (@x) { | sub product (@x) { |

    sub join (@x) { my $a = 0; | my $a = 1; | my $a = ''; | | $a += $_ for @x;| $a *= $_ for @x; | $a ~= $_ for @x; | | return $a; | return $a; | return $a; } | } | } 46
  21. sub sum (@x) { | sub product (@x) { |

    sub join (@x) { my $a = 0; | my $a = 1; | my $a = ''; | | $a += $_ for @x;| $a *= $_ for @x; | $a ~= $_ for @x; | | return $a; | return $a; | return $a; } | } | } 47
  22. sub sum (@x) { my $a = 0; $a +=

    $_ for @x; return $a; } 48
  23. sub sum (@x) { my $a = 0; $a =

    $a + $_ for @x; return $a; } 49
  24. sub reduce (@x) { my $a = 0; $a =

    $a + $_ for @x; return $a; } 50
  25. sub reduce (@x) { my $a = $init; $a =

    $a + $_ for @x; return $a; } 51
  26. sub reduce (@x, $init) { my $a = $init; $a

    = $a + $_ for @x; return $a; } 52
  27. sub reduce (@x, $init) { my $a = $init; $a

    = operation($a, $_) for @x; return $a; } 53
  28. sub reduce (&operation, @x, $init) { my $a = $init;

    $a = operation($a, $_) for @x; return $a; } 54
  29. sub sum (@x) { | sub product (@x) { |

    sub join (@x) { my $a = 0; | my $a = 1; | my $a = ''; | | $a += $_ for @x;| $a *= $_ for @x; | $a ~= $_ for @x; | | return $a; | return $a; | return $a; } | } | } 55
  30. sub sum (@x) { | sub product (@x) { |

    sub join (@x) { my $a = 0; | my $a = 1; | my $a = ''; | | $a += $_ for @x;| $a *= $_ for @x; | $a ~= $_ for @x; | | return $a; | return $a; | return $a; } | } | } my $total = reduce { $^a + $^b }, @fees, 0; my $factorial = reduce { $^a * $^b }, [1..5], 1; my $joined = reduce { $^a ~ $^b }, @out, ''; 56
  31. sub sum (@x) { return reduce { $^a + $^b

    }, @x, 0; } sub product (@x) { return reduce { $^a * $^b }, @x, 1; } sub join (@x) { return reduce { $^a ~ $^b }, @x, ""; } my $total = sum(@fees); my $factorial = product([1..5]); my $joined = join(@out); 57
  32. sub sum (@x) { return reduce { $^a + $^b

    }, @x, 0; } sub product (@x) { return reduce { $^a * $^b }, @x, 1; } sub join (@x) { return reduce { $^a ~ $^b }, @x, ""; } my $total = sum(@fees); my $factorial = product([1..5]); my $joined = join(@out); Javascript: sum = arr.reduce((a,x) => a+x, 0); 58
  33. sub reduce (&operation, @x, $init) { my $a = $init;

    $a = operation($a, $_) for @x; . return $a; } 59
  34. sub reduce (&operation, @x, $init) { my $a = @x.head;

    $a = operation($a, $_) for @x.skip; return $a; } 60
  35. sub reduce (&operation, @x) { my $a = @x.head; $a

    = operation($a, $_) for @x.skip; return $a; } 61
  36. sub sum (@x) { return reduce { $^a + $^b

    }, @x, 0; } sub product (@x) { return reduce { $^a * $^b }, @x, 1; } sub join (@x) { return reduce { $^a ~ $^b }, @x, ""; } my $total = sum(@fees); my $factorial = product([1..5]); my $joined = join(@out); 62
  37. sub sum (@x) { return reduce { $^a + $^b

    }, @x, 0; } sub product (@x) { return reduce { $^a * $^b }, @x, 1; } sub join (@x) { return reduce { $^a ~ $^b }, @x, ""; } my $total = sum(@fees); my $factorial = product([1..5]); my $joined = join(@out); 63
  38. sub sum (@x) { | sub product (@x) { |

    sub join (@x) { my $a = 0; | my $a = 1; | my $a = ''; | | $a += $_ for @x;| $a *= $_ for @x; | $a ~= $_ for @x; | | return $a; | return $a; | return $a; } | } | } my $total = [+] @fees; my $factorial = [*] 1..5; my $joined = [~] @out; 66
  39. “All these squares make a circle.” “All these squares make

    a circle.” “All these squares make a circle.”
  40. –Mr. Popo, after dropping a gallon of LSD Dragonball Z

    [Abridged] “All these squares make a circle.” “All these squares make a circle.” “All these squares make a circle.”
  41. my $total = @fees.sum; my $factorial = [*] 1..5; my

    $joined = @out.join; # There is a better way for factorial, though. 70
  42. [op] @a @a[0] op @a[1] op @a[2] op @a[3] …

    [+] @a @a[0] + @a[1] + @a[2] + @a[3] … 72
  43. my $o = [lt] @names; raku -e ' say [lt]

    <Alice Bob Carol>; say [lt] <Alice Carol Bob>; ' Output: True False @names[0] lt @names[1] lt @names[2] 74
  44. raku -e ' my @nodes = "A".."E"; my $tree =

    [=>] @nodes; say $tree.raku; say $tree; say (A => B => C => D => "E");' :A(:B(:C(:D("E")))) A => B => C => D => E A => B => C => D => E Audrey uses it as "linked list consing", for you LISP users. https://github.com/Raku/roast/blob/master/S03- metaops/reduce.t#L141 75
  45. A / \ B / \ C / \ D

    / \ E / \ 76
  46. say [\,] <a b c d>; # ((a) (a b)

    (a b c) (a b c d)) 82
  47. say "6! = ", [*] 1..6; 6! = 720 #

    Auto-caching! constant @factorials = 1, |[\*] 1..*; 83
  48. Z

  49. Ways to do array keys @a.keys -> $i { ^@a

    -> $i { 0 .. @a.end -> $i { 0 ..^ @a.elems -> $i { 0 ..^ @a -> $i { 0 ..^ +@a -> $i { 0 .. @a - 1 -> $i { 0 .. +@a - 1 -> $i { 0 .. @a.elems - 1 -> $i { 85
  50. Ways to do array keys @a.keys -> $i { ^@a

    -> $i { 0 .. @a.end -> $i { 0 ..^ @a.elems -> $i { 0 ..^ @a -> $i { 0 ..^ +@a -> $i { 0 .. @a - 1 -> $i { 0 .. +@a - 1 -> $i { 0 .. @a.elems - 1 -> $i { 86
  51. for @names.keys -> $i { my ( $name, $addr, $postal

    ) = @names[$i], @addrs[$i], @posts[$i]; … } 87
  52. for @names.keys -> $i { my ( $name, $addr, $postal

    ) = @names[$i], @addrs[$i], @posts[$i]; … } 88
  53. for @names.keys -> $i { my ( $name, $addr, $postal

    ) = @names[$i], @addrs[$i], @posts[$i]; … } 89
  54. for @names Z @addrs Z @posts -> ($name, $addr, $postal)

    { for ([Z] @names, @addrs, @posts) -> ($name, $addr, $postal) { for zip(@names, @addrs, @posts) -> ($name, $addr, $postal) { 91
  55. my @nap = @names Z @addrs Z @post; ( name0,

    addr0, post0 ), ( name1, addr1, post1 ), … my @nap = [Z] @names, @addrs, @post; 92
  56. .say for @names Z @addrs Z @post; .say for [Z]

    @names, @addrs, @post; .say for zip(@names, @addrs, @post); ( name0, addr0, post0 ), ( name1, addr1, post1 ), … 93
  57. my @a = 6, 9, 11, 13; my @diffs =

    @a.keys.skip .map({ [-] @a[$_, $_-1] }); @a.skip == 9, 11, 13 @a == 6, 9, 11, 13 subtract 3 2 2 . 95
  58. my @a = 6, 9, 11, 13; my @diffs =

    @a.skip Z- @a; @a.skip == 9, 11, 13 @a == 6, 9, 11, 13 subtract 3 2 2 . 96
  59. my @makes = <ford kia audi>; my @years = 2021..2023;

    for @makes -> $make { for @years -> $year { say "$make $year ", (%sales{$make}{$year} // 0); } } 102
  60. my @makes = <ford kia audi>; my @years = 2021..2023;

    for @makes -> $make { for @years -> $year { say "$make $year ", (%sales{$make}{$year} // 0); } } 103
  61. my @makes = <ford kia audi>; my @years = 2021..2023;

    for @makes -> $make { - for @years -> $year { say "$make $year ", (%sales{$make}{$year} // 0); } } 104
  62. my @makes = <ford kia audi>; my @years = 2021..2023;

    for @makes -> $make { . for @years -> $year { say "$make $year ", (%sales{$make}{$year} // 0); } . } 105
  63. my @makes = <ford kia audi>; my @years = 2021..2023;

    for @makes -> $make { for @years -> $year { say "$make $year ", (%sales{$make}{$year} // 0); } } 106
  64. my @makes = <ford kia audi>; my @years = 2021..2023;

    for @makes X @years -> ($make, $year) { say "$make $year ", (%sales{$make}{$year} // 0); } 107
  65. my @makes = <ford kia audi>; my @years = 2021..2023;

    for @makes -> $make { for @years -> $year { say "$make $year ", (%sales{$make}{$year} // 0); } } 108
  66. my @makes = <ford kia audi>; my @years = 2021..2023;

    for @makes X @years -> ($make, $year) { say "$make $year ", (%sales{$make}{$year} // 0); } 109
  67. my @makes = <ford kia audi>; my @years = 2021..2023;

    for @makes X @years -> ($make, $year) { say "$make $year ", (%sales{$make}{$year} // 0); } 110
  68. my @ages-this-year = 6, 9, 11, 13; my @nny =

    @ages-this-year; for @nny <-> $age { $age += 2; } 119
  69. my @ages-this-year = 6, 9, 11, 13; my @nny =

    @ages-this-year; $_ += 2 for @nny; 120
  70. my @n = 2, 4, 42; say sqrt [+] @n

    X** 2; say ( @n X** 2 ).sum.sqrt; # 42.23742416388575 # 42.23742416388575 125
  71. raku -e ' my @n = 2, 4, 42; say

    sqrt [+] @n X** 2; say ( @n X** 2 ).sum.sqrt; ' # 42.23742416388575 # 42.23742416388575 126
  72. https://theweeklychallenge.org/blog/perl-weekly- challenge-274/#TASK1 # TWC Goat Latin # Rule 3: Add

    letter "a" to the end of first word in the sentence, "aa" to the second word, etc. constant @as = "a" Xx (1..*); # (a aa aaa aaaa …) return ( $s.words.map(&goat_word) Z~ @as ).join:" "; 127
  73. 130 • High-level: • Promises • Supplies • Channels •

    react/whenever • Low-level: • Threads • Schedulers • Locks • Semaphores https://docs.raku.org/language/concurrency
  74. Goat Latin, revisited # (a aa aaa aaaa …) constant

    @as = "a" Xx (1..*); raku -e ' constant @as = "a" «x« (1..*); ' ===SORRY!=== Error while compiling -e An exception X::HyperOp::Infinite occurred while evaluating a constant: List on right side of hyperop of infix:<x> is known to be infinite 141
  75. https://en.wikipedia.org/wiki/ ISBN#ISBN-13_check_digit_calculation x₁ + 3x₂ + x₃ + 3x₄ +

    x₅ + 3x₆ + x₇ + 3x₈ + x₉ + 3x₁₀ + x₁₁ + 3x₁₂ + x₁₃ ≡ 0 (mod 10) (@digits Z* <1 3 1 3 1 3 1 3 1 3 1 3>).sum (@digits Z* |( (1,3) xx * ) ).sum (@digits »*» (1,3) ).sum 143
  76. raku -e 'my @a = [ [11,12], [13,14], [15,16] ],

    [ [21,22], [23,24], [25,26] ]; my @b = @a».rotate; my @c = @a »+» 1; say @b; say @c;' [ ( [13 14] [15 16] [11 12] ) ( [23 24] [25 26] [21 22] ) ] .rotate is nodal, so hyper only goes down 1 level [ [ [12 13] [14 15] [16 17] ] [ [22 23] [24 25] [26 27] ] ] `+` is not nodal, so every element incremented 145
  77. https://docs.raku.org/language/typesystem#trait_is_nodal trait is nodal Marks a List method to indicate

    to hyperoperator to not descend into inner Iterables to call this method. This trait generally isn't something end users would be using, unless they're subclassing or augmenting core List type. In order to demonstrate the difference consider the following examples, the first using a method (elems) that is nodal and the second using a method (Int) which is not nodal. say ((1.0, "2", 3e0), [^4], '5')».elems; # OUTPUT: «(3, 4, 1) ␤ » say ((1.0, "2", 3e0), [^4], '5')».Int # OUTPUT: «((1 2 3) [0 1 2 3] 5) ␤ » 146
  78. use nqp; for Str, Int, List, Array, Seq -> $type

    { my $b = $type.^methods .map({ nqp::can($_,"nodal") }).Bag; say $type.^name.fmt("%-7s: "), $b.raku; } Str : (0=>79).Bag Int : (0=>86).Bag List : (0=>37, 1=>36).Bag Array : (0=>63, 1=>51).Bag Seq : (0=>25, 1=>17).Bag 147
  79. use nqp; for Str, Int, List, Array, Seq -> $type

    { my $b = $type.^methods .map({ nqp::can($_,"nodal") }).Bag; say $type.^name.fmt("%-7s: "), $b.raku; } Str : ( 0=>79 ).Bag Int : ( 0=>86 ).Bag List : ( 0=>37, 1=>36 ).Bag Array : ( 0=>63, 1=>51 ).Bag Seq : ( 0=>25, 1=>17 ).Bag 148
  80. use nqp; say nqp::can( &prefix:<++>, "nodal" ); # 0 say

    nqp::can( List.^lookup("pairs"), "nodal" ); # 1 149
  81. raku -e ' use nqp; say nqp::can($_,"nodal"), " ", .name

    for List.^methods; ' | sort # Output on next 2 pages, grouped as `0` or `1`. 151
  82. 0 == not Nodal ACCEPTS ASSIGN-POS BIND-POS BUILDALL Bool Capture

    FLATTENABLE_HASH FLATTENABLE_LIST Int Numeric STORE Str chrs eager flat fmt from from-iterator from-slurpy from-slurpy-flat from-slurpy-onearg gist head hyper is-lazy item iterator lazy lazy-if new of race raku reification-target sink tail to 152
  83. 1 == Nodal AT-POS Array Bag BagHash EXISTS-POS List Mix

    MixHash Set SetHash Slip Supply antipairs append combinations elems end invert join keys kv list pairs permutations pick pop prepend push reverse roll rotate shift sort sum unshift values 153
  84. https://oeis.org/A104101 my @L = 4,8,15,16,23,42 ; my @L = <4

    8 15 16 23 42>; my @L = +«<4 8 15 16 23 42>; say .WHAT for @L.map; ((IntStr) (IntStr) (IntStr) (IntStr) (IntStr) (IntStr)) ((Int) (Int) (Int) (Int) (Int) (Int)) 154
  85. https://oeis.org/A104101 my @L = 4,8,15,16,23,42 ; my @L = <4

    8 15 16 23 42>; my @L = +«<4 8 15 16 23 42>; say .WHAT for @L.map; ((IntStr) (IntStr) (IntStr) (IntStr) (IntStr) (IntStr)) ((Int) (Int) (Int) (Int) (Int) (Int)) 155
  86. Copyright Information: Images • Camelia • © 2009 by Larry

    Wall
 http://github.com/perl6/mu/raw/master/misc/camelia.txt • Periodic Table of the Operators • © 2004, 2009 by Mark Lentczner
 https://www.ozonehouse.com/mark/periodic/ • Beer Barrel Keg Cask • by Steve Buissinne ; Free for use under the Pixabay Content License
 https://pixabay.com/photos/beer-barrel-keg-cask-oak-barrel-956322/
 https://pixabay.com/users/stevepb-282134/
 https://pixabay.com/service/terms/
  87. LICENSE • © 2024 Bruce Gray <[email protected]>
 This work is

    openly licensed under CC BY 4.0.
 https://creativecommons.org/licenses/by/4.0/