The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.

NAME

Worlogog::Restart - Lisp-style dynamic restarts

SYNOPSIS

use Worlogog::Restart -all => { -prefix => 'restart_' };

my $x = restart_case {
  restart_invoke 'foo', 21;
  die;  # not reached
} {
  foo => sub {
    return $_[0] * 2;
  },
};
print "$x\n";  # 42

my $y = restart_bind {
  my $x = restart_invoke 'bar', 20;
  return $x + 2;
} {
  bar => sub {
    return $_[0] * 2;
  },
};
print "$y\n";  # 42

DESCRIPTION

This module provides dynamic restarts similar to those found in Common Lisp. A restart is a bit like an exception handler or a dynamically scoped function. It can be invoked (by name) from any subroutine call depth as long as the restart is active.

Functions

The following functions are available:

invoke RESTART
invoke RESTART, ARGUMENTS

Invokes RESTART, passing it ARGUMENTS (if any) in @_. Returns whatever RESTART returns (provided it returns normally, which restarts established by case never do).

RESTART can be either a restart object (such as those returned by find or compute) or a restart name (a string). Names are looked up dynamically by searching outwards through all handlers established by bind or case. If no matching restart is found, this is an error and invoke dies.

bind BLOCK HASHREF

Executes BLOCK with the restarts specified by HASHREF, which maps restart names (strings) to handlers (subroutine references). Returns whatever BLOCK returns.

case BLOCK HASHREF

Executes BLOCK with the restarts specified by HASHREF, which maps restarts names (strings) to handlers (subroutine references). Returns whatever BLOCK returns (or what the corresponding restart returns if invoke is used to return from case).

Unlike bind, the restarts it establishes always unwind the stack first before running and thus ultimately return from case itself, not from invoke. That is, a restart established by case will implicitly return from all subroutines between case and invoke, then execute the handler body specified in HASHREF, then return from case.

find RESTART

Finds the restart that would be called by invoke at this point. Returns a restart object representing the restart or undef if no corresponding restart is active. RESTART must be a name (string).

Restart objects returned by find have the following methods:

$restart->name

Returns the name of the restart.

$restart->code

Returns the subroutine reference of the restart handler.

compute

Searches outwards and returns a list of restart objects representing all currently active restarts. The innermost restarts will be listed first.

The returned list may contain restarts that you can't normally invoke because they're shadowed by a more recent restart with the same name:

# prints "9" because the innermost 'foo' is listed first
print bind {
  bind {
    my @restarts = compute;
    #
    # $restarts[0]->name = 'foo'
    # $restarts[0]->code = sub { $_[0] + 2 }
    #
    # $restarts[1]->name = 'foo'
    # $restarts[1]->code = sub { $_[0] * 3 }

    my $x = 1;
    $x = invoke($_, $x) for @restarts;
    # $x = $x + 2
    # $x = $x * 3

    $x
  } {
    foo => sub { $_[0] + 2 },
  };
} {
  foo => sub { $_[0] * 3 },
};

This module uses Exporter::Tiny, so you can rename the imported functions at use time.

SEE ALSO

Exporter::Tiny, Return::MultiLevel

AUTHOR

Lukas Mai, <l.mai at web.de>

COPYRIGHT & LICENSE

Copyright 2013, 2014 Lukas Mai.

This program is free software; you can redistribute it and/or modify it under the terms of either: the GNU General Public License as published by the Free Software Foundation; or the Artistic License.

See http://dev.perl.org/licenses/ for more information.