Как стать автором
Обновить

Комментарии 15

Лучше предусмотреть возможность использования модуля в ООП режиме. Хотя для учебного материала это не особо нужно :)
предусмотрел :)

package MyMath;
our $VERSION = '0.01';

use strict;
use bigint;

use Recurrent;

sub new {
    bless {}, shift;
}

recurrent 'fib' => {
    arg(0) => lambda { my($n) = @_; return 0 },
    arg(1) => lambda { my($n) = @_; return 1 },
    arg(n) => lambda { my($n) = @_; return fib($n-1) + fib($n-2) },
};

1;


#!/usr/bin/perl -I./lib
use strict;
use bigint;

use Test::More tests => 2;
use MyMath;

is(MyMath->new->fib(100), MyMath::fib(100), "two modes");
is(MyMath->new->fib(100), 354224848179261915075, "fib(100)");


ok 1 — two modes
ok 2 — fib(100)

И все-таки лучше просто писать на Erlang.
почему?
минус — это аргументированный ответ
Я бы использовал confess, вместо croak, раз речь идёт и ловле ошибок программиста, а не юзера.
Так же lambda вместо sub — это уже дело вкуса… Мне вполне нравится sub, кстати в perl 5.10 часто можно просто поставить скобки {}.

Ещё, раз функция может быть от одной переменной, я бы использовал local $_, код тогда мог выглядеть так:

    arg(0) => sub { 0 },
    arg(1) => sub { 1 },
    arg(n) => sub { fib($_-1) + fib($_-2) },


$_ удобна тем что многие встроенные функции можно вызывать с этим неявным аргументом — defined, /someregexp/ chomp итд.

Передать $_ в функцию можно просто:
$mycallback->() for ($myarg);

хорошая идея с $_ :)
сделал, спасибо
можно еще так сделать
recurrent ƒ => {
    (0) => λ { 0 },
    (1) => λ { 1 },
    (N) => λ { ƒ(n-1) + ƒ(n-2) },
};


но не очень удобно будет что n и N различаются
sub N { '' }
sub n { $_ }
Можно сделать чтобы и там и там было n: перед вызовом лямбды переопределить n.
local *n = sub() {
...
}

Ещё из косметики — когда присваиваем глобу анонимную ф-цию, я обычно делаю такую штуку:

use Sub::Name;
*foo = subname foo => sub{};


Очень помогает при отладке видеть, что упало не в некоей __ANON__, которых может быть 3-4 подряд по стеку, а именно в foo().
use v5.14;
use Memoize;
use List::Util qw(sum reduce);

memoize 'fib';
say sum map fib($_), 1..100; # "sum" is a "reduce { $a + $b }"

sub fib {
    my $n = shift;
    return $n if $n < 2;
    fib($n-1) + fib($n-2);
}
Да, только хотел про Memoize написать :) Очень полезная штука.
если заюзать state и __SUB__, то можно так:

use v5.16;
use List::Util 'sum';

say sum map {
    state $fib = sub {
        my $n = shift;
        state $cache = [];
        $cache->[$n] //= $n < 2 ? $n : __SUB__->($n-1) + __SUB__->($n-2);
    };
    $fib->($_);
} 1..100;
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации