#!/usr/bin/env perl
# Copyright (c) 2019 Christian Jaeger, copying@christianjaeger.ch
# This is free software. See the file COPYING.md that came bundled
# with this file.
use
strict;
use
warnings;
# find modules from functional-perl working directory (non-installed)
our
(
$mydir
,
$myname
);
BEGIN {
my
$location
= (-l $0) ? abs_path($0) : $0;
$location
=~ /(.*?)([^\/]+?)_?\z/s or
die
"?"
;
(
$mydir
,
$myname
) = ($1, $2);
}
# Comparison of imperative and functional approaches to some data
# container:
package
ImperativePerson {
has
name
=>
is
=>
'ro'
;
has
todo_items
=>
is
=>
'ro'
;
# the array itself is the mutable part
sub
add_todo {
my
(
$self
,
$item
) =
@_
;
push
@{
$self
->{todo_items} },
$item
;
}
}
package
FunctionalPerson {
sub
add_todo {
my
(
$self
,
$item
) =
@_
;
# The sub receives the old todo_items list, and returns a new
# list with $item prepended:
#$self->todo_items_update(sub { cons $item, $_[0] })
# Or use `cons_` which returns a function that prepends
# cons_'s argument to its own argument:
$self
->todo_items_update(cons_
$item
)
}
_END_
}
use
Test::More;
sub
testImperative {
my
$p
= ImperativePerson->new(
name
=>
"Chris"
,
todo_items
=> []);
$p
->add_todo(
"buy bread"
);
$p
->add_todo(
"walk dog"
);
is_deeply
$p
->todo_items, [
'buy bread'
,
'walk dog'
];
}
# reporting via Test::More
sub
testFunctional {
my
$p
= FunctionalPerson->new_(
name
=>
"Chris"
,
todo_items
=> list());
# or, using positional arguments:
#my $p = FunctionalPerson->new("Chris", list());
# Each add_todo call returns a new version of the object, any
# pointer to the old version still sees the original value:
my
$p2
=
$p
->add_todo(
"buy bread"
);
my
$p3
=
$p2
->add_todo(
"walk dog"
);
is_equal
$p3
->todo_items, list(
'walk dog'
,
'buy bread'
);
is_equal
$p2
->todo_items, list(
'buy bread'
);
}
if
(
$ENV
{RUN_TESTS}) {
testImperative;
testFunctional;
done_testing;
}
else
{
import
FunctionalPerl
":repl"
;
repl();
}