Skip to content

Instantly share code, notes, and snippets.

@dhilst
Last active February 9, 2026 04:45
Show Gist options
  • Select an option

  • Save dhilst/cc286577a072835a3f0e28234a14c3eb to your computer and use it in GitHub Desktop.

Select an option

Save dhilst/cc286577a072835a3f0e28234a14c3eb to your computer and use it in GitHub Desktop.
use v5.10;
use Data::Dumper;
use Carp;
use Test::More;
sub aref { \@_ }
package Opt {
use overload
'""' => \&stringinfy;
sub new {
my ($cls, $tag, $payload) = @_;
bless {
tag => $tag,
payload => $payload,
}, $cls;
}
sub value {
shift->{payload};
}
sub some {
Opt->new("some", shift);
}
sub none {
Opt->new("none");
}
sub is_some {
shift->{tag} eq "some";
}
sub map(&$) {
my ($block, $self) = @_;
if ($self->is_some) {
local $_ = $self->value;
return some($block->());
} else {
return $self;
}
}
sub default(&$) {
my ($block, $self) = @_;
return $block->() unless $self->is_some;
$self->value;
}
sub stringinfy {
my ($self) = @_;
if ($self->is_some) {
return "Some(" . $self->value . ")";
} else {
return "None"
}
}
sub bind(&$) {
my ($block, $self) = @_;
if ($self->is_some) {
local $_ = $self->value;
return $block->();
} else {
return $self;
}
}
sub match($%) {
my ($self, %opts) = @_;
local $_ = $self->value;
$opts{$self->{tag}}->();
}
}
package Opt::Match {
sub some(&$) {
my ($block, $self) = @_;
return $self unless ref($self) eq "Opt";
if ($self->is_some) {
local $_ = $self->value;
return $block->();
} else {
return $self;
}
}
sub none(&$) {
my ($block, $self) = @_;
return $self unless ref($self) eq "Opt";
if (! $self->is_some()) {
local $_ = undef;
return $block->();
} else {
return $self;
}
}
}
my $some = Opt::some(1);
my $none = Opt::none();
is(
do {
# execution flows bottom up
Opt::default { "oops" }
Opt::map { $_ * 2 }
Opt::map { $_ + 1 }
$some;
},
4
);
is(
do {
# execution flows bottom up
Opt::Match::some { 111 }
Opt::Match::none { 222 }
Opt::bind { $_ > 0 ? Opt::some($_ - 1) : Opt::none() }
Opt::bind { $_ > 0 ? Opt::some($_ - 1) : Opt::none() }
Opt::none();
},
222);
is(
Opt::match($none,
some => sub { $_ + 100 },
none => sub { 999 }),
999
)
;
done_testing;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment