package Backtracking; $VERSION = 0.03; use strict; use Carp; sub import { while (my $arg = shift) { # process args if ($arg eq 'filter') { croak "'filter' option to Backtracking must be specified last!\n" if @_; require Filter::Util::Call; import Filter::Util::Call; filter_add( sub { my ($status, $no_seen, $data); my $count = 0; while ($status = filter_read()) { return $status if $status < 0; if (/\bno\s+Backtracking\s+'filter'\s*;\s*$/) { $no_seen=1; last; } $data .= $_; $_ = ""; $count++; } $_ = $data; s/\bgoal([\r\n\s]+)(\w+)([\r\n\s]*\{)/Backtracking::goal $1 '$2' => sub $3/g unless $status < 0; $_ .= "no Backtracking 'filter';\n" if $no_seen; $count; } ); } elsif ($arg eq 'goal') { my ($package) = caller; no strict 'refs'; *{$package."::goal"} = \&goal; } } } sub unimport { filter_del() if $_[0] eq 'filter'; } sub goal($&) { my ($name,$code) = @_; my ($package) = caller; no strict 'refs'; my $btarray = $package.'::BACKTRACK_'.$name; push @{$btarray},$code; if (@{$btarray} == 2) { eval " sub $package".'::'."$name { for (@".$btarray.") { my \$rv = \$_->(\@_); return \$rv if \$rv; } return; } 1; " or croak $@; } } 1; __END__ =pod =head1 NAME Backtracking =head1 DESCRIPTION A very simple backtracking mechanism. =head1 SYNOPSIS use Backtracking qw(goal filter); goal is_member { # filter syntax my ($x,$y,@list) = @_; return $x eq $y; }; goal is_member => sub { # goal syntax my ($x,undef,@list) = @_; return unless @list; return is_member($x,@list); }; for (qw(a b c d e f)) { if (is_member($_,qw(a b c d e))) { print "$_ is a member\n"; } else { print "$_ is not a member\n"; } } # That should print a is a member b is a member c is a member d is a member e is a member f is not a member =head1 KNOWN BUGS / CAVEATS =over 4 =item * All goals are run in SCALAR context. This might be changed in the future. =item * There is no statement to express a 'cut'. =item * If you have the C package installed, you can C to turn something like: goal goal1 { ... }; into goal 'goal1' => sub { .... }; using the following regex: s/\bgoal([\r\n\s]+)(\w+)([\r\n\s]*\{)/Backtracking::goal $1 '$2' => sub $3/g This might mismatch sometimes. =back =head1 SEE ALSO L, L =head1 AUTHOR Joost Diepenmaat - joost@hortus-mechanicus.net