Implementation of a function object “power” operator in Raku

20

In APL there is the power operator , which if applied to a function f superimposes the application of f. How to implement that operator in Raku?

For example, with this definition of f:

sub f(Int:D $i){ $i + 1 }

the command say (f ⍣ 4)(10); should be equivalent to say f(f(f(f(10))));.

My implementation below is for a function with one argument.

Questions

  1. How one should extend or replace it with a better implementation that works on multiple (or any) signatures?

  2. How to define "high precedence" of that new power operator?

  3. Is there are better way to define the "identity function" result for f ⍣ 0?

Reference links

Here is a description of APL's : "Power Operator".

( is a "star with two dots", or more formally "Apl Functional Symbol Star Diaeresis".)

Attempt

Here is an attempt of an implementation:

sub infix:<⍣>( &func, Int:D $times where $times >= 0 ) {
    if $times == 0  {
      sub func2($d) {$d}
    } else {
      sub func2($d) {
        my $res = &func($d);
        for 2..$times -> $t { $res = &func($res) }
        $res
      }
    }
}

sub plus1(Int:D $i){ $i + 1 }

say 'Using (&plus1 ⍣ 0) over 4 :';
say (&plus1 ⍣ 0)(4);

say 'Using (&plus1 ⍣ 10) over 4 :';
say (&plus1 ⍣ 10)(4);

# Using (&plus1 ⍣ 0) over 4 :
# 4
# Using (&plus1 ⍣ 10) over 4 :
# 14

(I followed this tutorial page: https://docs.raku.org/language/optut .)

Tests

The definition provided by Brad Gilbert's answer passes all of the tests below.

use Test;

sub infix:<⍣> ( &func, UInt $repeat ) is tighter( &[∘] ) { [∘] &func xx $repeat }

proto plus1(|) {*}
multi plus1(Int:D $i){ $i + 1 }
multi plus1(Bool:D $b){ $b.Int + 1 }
multi plus1(Int:D $i, Bool:D $b){ $i + $b.Int + 1 }
multi plus1(Int:D $i, Int:D $j){ $i + $j + 1 }
multi plus1(@j){ ([+] @j) + 1}
multi plus1(Int:D $i, @j){ plus1($i) + plus1(@j) - 1 }
multi plus1(%h){ ([+] %h.values) + 1 }

plan 9;

is plus1([1, 3, 5, 3]), 13, 'plus1([1, 3, 5, 3])';

is plus1(3, [1, 3, 5, 3]), 16, 'plus1(3, [1, 3, 5, 3])';

is plus1(3, True), 5, 'plus1(3, True)';

is (&plus1 ⍣ 0)(4), 4, '(&plus1 ⍣ 0)(4)';

is (&plus1 ⍣ 10)(4), 14, '(&plus1 ⍣ 10)(4)';

is (&plus1 ⍣ 10)([1, 3, 5, 3]), 22, '(&plus1 ⍣ 10)([1, 3, 5, 3])';

is (&plus1 ⍣ 3)(4, True), 8, '(&plus1 ⍣ 3)(4, True)';

is (&plus1 ⍣ 3)(3, [1, 3, 5, 3]), 18, '(&plus1 ⍣ 3)(3, [1, 3, 5, 3])';

is (&plus1 ⍣ 3)({a => 1, b => 3, c => 5}), 12, '(&plus1 ⍣ 3)({a => 1, b => 3, c => 5})';

done-testing;
Share
Improve this question
1
  • 1
    Note that ([+] @j) can be written as [+]( @j ) (No spaces between ] and (). You could also write it without parens at all 1 + [+] @j or [+] 1, |@j – Brad Gilbert 3 hours ago

Comments

Popular posts from this blog

Meaning of `{}` for return expression

Get current scroll position of ScrollView in React Native

flutter websocket connection issue