“Действительно ли карта” является циклом?

При ответе на этот вопрос я пришел к пониманию, что не был уверен ли Perl map может считаться циклом или нет?

С одной стороны, это шарлатаны/обходы как цикл (делает O (n) работа, может быть легко переписан эквивалентным циклом и видом соответствий общее определение = "последовательность инструкций, которая постоянно повторяется").

С другой стороны, map обычно не перечисляется среди управляющих структур Perl, из которых циклы являются подмножеством. Например, http://en.wikipedia.org/wiki/Perl_control_structures#Loops

Так, что я ищу, формальная причина, которая будет убеждена в одной стороне по сравнению с другим. До сих пор первый (это - цикл) звучит намного более убедительным мне, но я побеспокоен тем, что я никогда не видел "карту", упомянутую в списке циклов Perl.

39
задан Community 23 May 2017 в 12:25
поделиться

13 ответов

«Цикл» - это скорее термин CS, нежели специфичный для языка. Вы можете быть достаточно уверены в вызове чего-либо цикла, если он демонстрирует следующие характеристики:

  • выполняет итерацию по элементам
  • делает то же самое каждый раз, когда
  • O (n)

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

2
ответ дан 27 November 2019 в 02:06
поделиться

Функция map не является циклом в Perl. Это ясно видно по неудачам next , redo и last внутри карты :

perl -le '@a = map { next if $_ %2; } 1 .. 5; print for @a'
Can't "next" outside a loop block at -e line 1.

Для достижения желаемого аффекта в карте , вы должны вернуть пустой список:

perl -le '@a = map { $_ %2 ? () : $_ } 1 .. 5; print for @a'
2
4

Я думаю, что преобразование - лучшее название для таких конструкций, как карта . Он преобразует один список в другой. Функция, аналогичная map , - это List :: Util :: reduce , но вместо преобразования списка в другой список она преобразует список в скалярное значение. Используя слово «преобразование», мы можем говорить об общих аспектах этих двух функций высшего порядка.

Тем не менее, он работает, посещая каждого члена списка. Это означает, что он ведет себя во многом как цикл, и в зависимости от вашего определения «цикла» он может быть квалифицирован. Обратите внимание, мое определение означает, что в этом коде также нет цикла:

#!/usr/bin/perl

use strict;
use warnings;

my $i = 0;
FOO:
    print "hello world!\n";
goto FOO unless ++$i == 5;

Perl фактически определяет словарный цикл в своей документации:

   loop
       A construct that performs something repeatedly, like a roller
       coaster.

Согласно этому определению, map является цикл, потому что он многократно преформирует свой блок; однако он также определяет «оператор управления циклом» и «метку цикла»:

   loop control statement
       Any statement within the body of a loop that can make a loop
       prematurely stop looping or skip an "iteration".  Generally you
       shouldn't try this on roller coasters.

   loop label
       A kind of key or name attached to a loop (or roller coaster) so
       that loop control statements can talk about which loop they want to
       control.

Я считаю неточным вызывать map цикл, потому что next и его родственники определены как операторы управления циклом , и они не могут управлять картой .

Это все просто игра словами. Описание map как петли - это совершенно верный способ познакомить кого-то с ней.Даже документация для map использует цикл foreach как часть своего примера:

               %hash = map { get_a_key_for($_) => $_ } @array;

           is just a funny way to write

               %hash = ();
               foreach (@array) {
                   $hash{get_a_key_for($_)} = $_;
               }

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

12
ответ дан 27 November 2019 в 02:06
поделиться

Ваш вопрос касается проблемы классификации. По крайней мере, согласно одной интерпретации, вопрос о том, является ли карта циклом, подобен вопросу о том, является ли карта подмножеством «Цикла». В такой постановке я думаю, что ответ отрицательный. Хотя map и Loop имеют много общего, есть важные различия.

  • Контроллер цикла : Chas.Оуэнс приводит веские доводы , что циклы Perl подчиняются элементам управления циклами, таким как next и last , а map - нет.
  • Возвращаемые значения : цель map - это возвращаемое значение; с петлями, не так уж и много.

Мы постоянно сталкиваемся с подобными отношениями в реальном мире - вещами, которые имеют много общего друг с другом, но ни один из них не является идеальным подмножеством другого.

 -----------------------------------------
|Things that iterate?                     |
|                                         |
|      ------------------                 |
|     |map()             |                |
|     |                  |                |
|     |          --------|----------      |
|     |          |       |          |     |
|     |          |       |          |     |
|      ------------------           |     |
|                |                  |     |
|                |              Loop|     |
|                 ------------------      |
|                                         |
 -----------------------------------------
11
ответ дан 27 November 2019 в 02:06
поделиться

С академической точки зрения, в зависимости от того, как определяется карта, могут быть рассмотрены оба варианта. Если он всегда выполняет итерацию по порядку, то цикл foreach может быть эмулирован с помощью map , делающей два эквивалента. Некоторые другие определения map могут допускать выполнение списка вне очереди для повышения производительности (разделение работы между потоками или даже отдельными компьютерами). То же самое можно сделать с конструкцией foreach .

Но что касается Perl 5, map всегда выполняется по порядку, что делает его эквивалентным циклу. Внутренняя структура выражения map $ _ * 2, 1, 2, 3 приводит к следующим кодам операций порядка выполнения, которые показывают, что map внутренне построена как while -подобная структура управления:

OP  enter
COP nextstate
OP  pushmark
SVOP const IV 1
SVOP const IV 2
SVOP const IV 3
LISTOP mapstart
LOGOP (0x2f96150) mapwhile  <-- while still has items, shift one off into $_
    PADOP gvsv GV *_            
    SVOP const IV 2             loop body
    BINOP multiply              
    goto LOGOP (0x2f96150)  <-- jump back to the top of the loop
LISTOP leave 
19
ответ дан 27 November 2019 в 02:06
поделиться

карта - это концепция более высокого уровня, чем циклы, заимствованная из функционального программирования. Он не говорит «вызовите эту функцию для каждого из этих элементов, один за другим, от начала до конца», он говорит: «вызывайте эту функцию для всех этих элементов». Он может быть реализован как цикл, но не в этом суть - он также может быть реализован асинхронно - это все равно будет карта.

Кроме того, это не совсем структура управления сама по себе - что, если бы каждая функция Perl, которая использовала цикл в своей реализации, была указана в разделе «циклы»? Тот факт, что что-то реализовано с использованием цикла, не означает, что это следует рассматривать как отдельный тип цикла.

30
ответ дан 27 November 2019 в 02:06
поделиться
Карта

- это функция высшего порядка . То же самое и с grep. Книга Perl высшего порядка объясняет идею во всех деталях.

Печально видеть, что обсуждение перешло к деталям реализации, а не к концепции.

10
ответ дан 27 November 2019 в 02:06
поделиться

Нет, с моей точки зрения, это не петля.

Циклы (perl) характеризуются тем, что они могут быть прерваны ( last ) или возобновлены ( next , redo ). map не может:

map { last } qw(stack overflow);  # ERROR!  Can't "last" outside a loop block

Сообщение об ошибке предполагает, что сам perl не считает оцениваемый блок блоком цикла .

26
ответ дан 27 November 2019 в 02:06
поделиться

Я думаю о map как о более близком операторе, например, умножения. Можно даже представить целочисленное умножение как цикл сложений :). Это, конечно, не цикл, даже если бы он был глупо реализован таким образом. Я вижу карту аналогично.

1
ответ дан 27 November 2019 в 02:06
поделиться

Сама карта обычно реализуется с использованием цикла некоторого вида (обычно для перебора итераторов), но поскольку это структура более высокого уровня, она часто не включается в списки более низких -уровневые управляющие структуры.

3
ответ дан 27 November 2019 в 02:06
поделиться

Все зависит от того, как вы на это смотрите...

С одной стороны, map языка Perl можно считать циклом, хотя бы потому, что именно так он реализован в (текущих версиях) Perl.

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

.
1
ответ дан 27 November 2019 в 02:06
поделиться

Ответы FM и Дэйва Шерохмана довольно хороши, но позвольте мне добавить дополнительный способ просмотра карты.

map - это функция, которая гарантированно просматривает каждый элемент структуры ровно один раз . И это не структура управления , поскольку она (сама) является чистой функцией. Другими словами, инварианты , которые сохраняет отображение, очень сильны, намного сильнее, чем «петля». Так что, если вы можете использовать карту, это здорово, потому что тогда вы получаете все эти инварианты «бесплатно», а если вы используете (более общую!) Структуру управления, вам придется установить все эти инварианты самостоятельно, если вы хочу быть уверенным, что ваш код верен.

И в этом действительно прелесть многих функций высшего порядка: вы получаете гораздо больше инвариантов бесплатно, так что вы, как программист, можете тратить свое драгоценное время на размышления, поддерживая инварианты, зависящие от приложения, вместо того, чтобы беспокоиться о низкоуровневых инвариантах. вопросы, связанные с реализацией.

4
ответ дан 27 November 2019 в 02:06
поделиться

Я думаю, что map соответствует определению Functor .

2
ответ дан 27 November 2019 в 02:06
поделиться

Вот определение map как рекурренции:

sub _map (&@) {
    my $f = shift;

    return unless @_;

    return $f->( local $_ = shift @_ ),
           _map( $f, @_ );
}

my @squares = _map { $_ ** 2 } 1..100;
3
ответ дан 27 November 2019 в 02:06
поделиться
Другие вопросы по тегам:

Похожие вопросы: