Home > Raku > Custom when

Custom when

I didn’t quite like the syntax of using match in the last post. The commas in the list of its arguments looked strangely out of place. Maybe because my eyes are used to a given block. Sleeping over it helped.

sub accord(&c) { (c(CALLER::<$_>); succeed) if &c.cando(\(CALLER::<$_>)) }

given Err.new(:msg<a>) {
    accord -> Hold (:$key) { put „holding $key“; }
    accord -> Err (:$msg) { warn „ERR: $msg“ }
    default { fail ‚unsupported‘ }
}

This works because accord mimics what when is doing. It does some matching, calls a block when True and adds a succeed (by throwing a control exception) at the end of each block. All given is doing is setting the topic. It also acts as a CALLER so we can access its $_ via a pseudo package. Using the signature of a pointy to do deconstruction is quite powerful. Adding this to CORE might be a good idea.

We may have to change the definition of Rako to: “Raku is a highly composable programming language, where things just fall into place.”

UPDATE:

There are cases where $_ is not a dynamic. Also, succeed is throwing a control exception and the handler for those are added by when or default. This happens at compile time and can’t currently be done with macros. The first problem is solvable with black magic. The latter requires a default-block. I didn’t find a way to provide a sensible error message if that block is missing.

multi sub accord(&c) {
    use nqp;
    $_ := nqp::getlexcaller('$_');
    (c($_); succeed) if &c.cando(\($_))
}

for @possibilities.roll(1) -> $needle {
    given $needle {
        accord -> Hold (:$key) { put „holding $key“; }
        accord -> Err (:$msg) { warn „ERR: $msg“ }
        default { warn ‚unsopported‘ }
    }
}
Categories: Raku
  1. CIAvash
    October 24, 2021 at 12:38

    I tried your code, `.cando(\($_))` doesn’t seem to work correctly. I changed it to:

    sub accord (&c) {
    use nqp;
    my $capture = nqp::getlexcaller(‘$_’).List.Capture;
    if &c.cando($capture) {
    c(|$capture);
    succeed;
    }
    }

    If `leave` was implemented, maybe we could use that instead of `succeed`, given the behavior of `when`.

    For error message I tried something hacky:

    CATCH {
    when X::ControlFlow {
    my $interesting_index = .backtrace.next-interesting-index: :named;
    die ‘No default block was provided’ if .illegal eq ‘succeed’ && $interesting_index == 2 && .backtrace[$interesting_index].subname eq &?ROUTINE.name;
    }
    }

  2. CIAvash
    October 24, 2021 at 19:23

    I’m not sure now, `\($_)` is probably correct.

  1. March 1, 2021 at 19:09
  2. April 21, 2021 at 22:38

Leave a comment