Под ссылками в качестве аргументов - PullRequest
2 голосов
/ 18 января 2011

Еще один вопрос для начинающих на Perl, но, как ни странно, я не нашел учебника, который бы объяснил мне эту простую проблему.

В качестве упражнения я хотел написать функцию map, которая принимает функцию и массив, возвращая массив. На функциональных языках это используется довольно часто, и я слышал о под-ссылках и как их использовать.

sub map {
  my $f = shift;
  my @r = ();

  foreach (@_) {
    push(@r, &f($_));
  }
  return @r;
}

sub square {
  my $r = shift;
  return $r*$r;
}

print map(\&shift, 1, 2, 3, 4, 5);

Но по какой-то причине я получаю только слово CODE и шестнадцатеричное число в качестве выходных данных пять раз. Затем я изменил вызов f в map на $$f($_) и $f->($_), но все они имели одинаковый результат.

Что я здесь не так делаю?

Ответы [ 2 ]

6 голосов
/ 18 января 2011
  1. Perl имеет встроенную функцию map. давайте назовем это map2

  2. используйте &$f для разыменования $f

  3. используйте join для правильной печати массива


sub map2 {
  my $f = shift;
  my @r = ();

  foreach (@_) {
    push(@r, &$f($_));
  }
  return @r;
}

sub square {
  my $r = shift;
  return $r*$r;
}

print join ",", map2(\&square, 1, 2, 3, 4, 5);

$ perl 1.pl
1,4,9,16,25
1 голос
/ 19 января 2011

Как уже упоминалось в комментариях, в Perl есть встроенная функция map, которую вы должны использовать.

my @squares = map {$_ ** 2} 1 .. 5;

Вместо передачи аргумента, встроенная в Perl map устанавливает $_ для каждого элемента, что позволяет вам писать вашу square функцию кратко как {$_ * $_} или {$_ ** 2}

Но Perl также дает вам возможность создавать пользовательские функции, подобные карте с аналогичным синтаксисом.Например, предположим, что вы хотите написать версию map, которая отображает пары значений:

sub pair_map (&@) {     # the (&@) prototype here tells perl that the sub
    my $code = shift;   # takes a code block, and then a list, just like `map`
    my @ret;        
    while (@_) {
        push @ret, $code->(splice @_, 0, 2);
    }
    @ret
}

my @pairs = pair_map {\@_} 1 .. 10;

pair_map {print "$_[0]: $_[1]\n"} %hash;

Но поскольку Perl уже давно, большинство служебных функций, вероятно, уже написаны.Поиск CPAN приведет к появлению многих map -подобных функций, выполняющих различные операции.

Я обнаружил, что мне часто приходится отображать списки с различными размерами шагов, поэтому я написал функцию mapn в Список :: Gen .Это полностью разработанное решение, поэтому оно включает в себя оптимизацию при вызове в пустом контексте и возвращается к собственному Perl map, когда n == 1:

sub mapn (&$@) {
    my ($sub, $n, @ret) = splice @_, 0, 2;
    croak '$_[1] must be >= 1' unless $n >= 1;

    return map $sub->($_) => @_ if $n == 1;

    my $want = defined wantarray;
    while (@_) {
        local *_ = \$_[0];
        if ($want) {push @ret =>
              $sub->(splice @_, 0, $n)}
        else {$sub->(splice @_, 0, $n)}
    }
    @ret
}

Оба pair_map и mapn используютрасширенная функция подпрограмм Perl, называемая прототипами.Эти прототипы не являются инструментами проверки аргументов (как во многих других языках).Скорее, они говорят Perl интерпретировать вызовы функций особым образом (аналогично тому, как используются некоторые другие встроенные функции).В этом случае, часть & прототипа сообщает Perl, что первый аргумент этих функций может быть записан как пустой блок, как обычный вызов map.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...