Какие функции динамического программирования Perl следует использовать?

Я новичок в написании языков (особенно в Perl), и большая часть кода, который я пишу, - это бессознательное усилие конвертировать C-код в Perl.

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

Все, что хорошо, но какие конкретные функции я должен иметь, имея некоторый опыт работы на C и С++, помнить при написании кода в Perl, чтобы использовать все функции динамического программирования, которые он имеет, для создания какого-нибудь удивительного кода?

Ответ 1

Этот вопрос более чем достаточно, чтобы заполнить книгу. На самом деле, это именно то, что произошло!

Отличный Perl Mark Jason Dominus, отличный от Perl, доступен онлайн бесплатно.

Вот цитата из этого предисловия, которая действительно схватила меня за горло, когда я впервые прочитал книгу:

Примерно в 1993 году я начал читать книги о Lisp, и я обнаружил что-то Важно: Perl намного больше похож на Lispчем это похоже на C. Если вы возьмете хорошая книга о Lisp, там будет раздел, который описывает Lisp s good функции. Например, книга Парадигмы искусственного интеллекта Программирование Питера Норвига включает раздел "Что делает LispДругой? который описывает семь функции Lisp. Perl делится шестью эти особенности; C никого из них не имеет. Это большие, важные функции, такие функции, как первоклассные функции, динамический доступ к таблице символов, и автоматическое управление хранилищем.

Ответ 2

Список привычек C не переносить на Perl 5:

  • Не объявляйте свои переменные в верхней части программы/функции. Объявляйте их по мере необходимости.
  • Не назначайте пустые списки массивам и хэшам при их объявлении (они уже пусты и должны быть инициализированы).
  • Не используйте if (!(complex logical statement)) {}, то есть для unless.
  • Не используйте goto для разбиения глубоко вложенных циклов, next, last и redo все принимают метку цикла в качестве аргумента.
  • Не используйте глобальные переменные (это общее правило даже для C, но я нашел, что многие люди C любят использовать глобальные переменные).
  • Не создавайте функцию, в которой будет выполняться закрытие (обратные вызовы в частности). См. perldoc perlsub и perldoc perlref для получения дополнительной информации. информация.
  • Не используйте in/out return, вместо этого возвращайте несколько значений.

Чем заняться в Perl 5:

  • Всегда используйте прагмы strict и warnings.
  • Прочитайте документацию (perldoc perl и perldoc -f function_name).
  • Используйте хеши, как вы использовали structs в C.

Ответ 3

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

Ваша цель не должна заключаться в поиске проблем для ваших решений. Узнайте немного больше Perl, чем вы планируете использовать сразу (и продолжайте учиться). Однажды вы столкнетесь с проблемой и подумаете: "Я помню что-то, что может помочь в этом".

Возможно, вам захочется увидеть некоторые из этих книг:

  • Perl более высокого порядка
  • Освоение Perl
  • Эффективное программирование на Perl

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

Ответ 4

Я думаю, что самым большим препятствием будет не динамический аспект, а аспект "батареи включены".

Я думаю, что самые мощные аспекты perl -

  • хэши: они позволяют легко выразить очень эффективные структуры данных.
  • регулярные выражения: они действительно хорошо интегрированы.
  • использование переменных по умолчанию, таких как $_
  • библиотеки и CPAN для всех, не установленных стандартных

Что-то, что я заметил с помощью C-конвертеров, - это использование циклов for. Многие могут быть удалены с помощью grep и map

Другим девизом perl является "есть более чем один способ сделать это". Чтобы подняться на кривой обучения, вам приходится часто говорить себе: "Там должен быть лучший способ сделать это, я не могу быть первым, кто хочет сделать...". Затем вы обычно можете обратиться к google и CPAN с его хрупким количеством библиотек.

Кривая обучения perl не крутая, но она очень длинная... не торопитесь и наслаждайтесь поездкой.

Ответ 5

Две точки.

Во-первых, в общем, я думаю, вы должны задавать себе 2 несколько разных вопроса:

1) Какие функции динамического программирования Perl могут использоваться в ситуациях/для решения каких проблем?

2) Каковы компромиссы, подводные камни и недостатки каждой функции.

Тогда ответ на ваш вопрос становится чрезвычайно очевидным: вы должны использовать функции, которые лучше решают вашу проблему (производительность или удобство обслуживания кода), чем сопоставимое решение, отличное от DP, и которое берет на себя меньше, чем максимальный доступный уровень недостатков.

В качестве примера, для цитаты из комментария FM, строковая форма eval имеет некоторые довольно неприятные недостатки; но в некоторых случаях МОЖЕТ быть чрезвычайно элегантным решением, которое на порядки лучше, чем любой альтернативный подход DP или SP.


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

Мне нужно подумать о наборе хороших примеров, но тот, который сразу приходит на ум, - это модули шаблонов текста, многие из которых реализованы с использованием вышеупомянутой строковой формы eval; или Try:: Крошечный механизм исключения, который использует блочную форму eval.

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

Ответ 6

Большинство других комментариев здесь завершены, и я не буду их повторять. Я сосредоточу внимание на моем личном предвзятости в отношении чрезмерного или недостаточного использования языковых идиом на языке, на котором вы пишете код. По мере того как вы можете писать C, можно писать C на любом языке. Также можно писать нечитаемый код на любом языке.

Я учился на C и С++ в колледже и позже взял Perl. Perl невероятно подходит для быстрых решений и некоторых действительно долговечных решений. Я построил компанию на Perl и Oracle для решения логистических решений для DoD с примерно 100 активными программистами. У меня также есть некоторый опыт в управлении привычками других программистов Perl, новых и старых. (Я был основателем/генеральным директором, а не техническим руководством, однако...)

Я могу только прокомментировать мой переход к программисту Perl и то, что я увидел в своей компании. Многие из наших инженеров поделились моим опытом, прежде всего, программистами на C/С++ по обучению и программистам на Perl по выбору.

Первый вопрос, который я видел (и имел сам), - это писать такой идиоматический код, что он непрочитан, не поддаётся контролю и неприменим после короткого периода времени. Perl и С++ разделяют способность писать сложный код, который интересен для понимания на данный момент, но вы забудете, а не вокруг, а другие не получат его.

Мы наняли (и уволили) многих программистов за 5 лет, когда у меня была компания. Общим вопросом интервью было следующее: Напишите короткую программу Perl, которая будет печатать все нечетные числа от 1 до 50 включительно, разделенные пробелом между каждым числом и заканчивающимся CR. Не используйте комментарии. Они могут делать это в свое время через несколько минут и могут сделать это на компьютере, чтобы проверить выход.

После того, как они написали script и объяснили это, мы попросим их изменить его, чтобы напечатать только эвенты (перед интервьюером), затем иметь образец результатов, основанный на каждой отдельной цифре, даже каждый нечетный, за исключением каждого седьмого и 11-го в качестве примера. Другим потенциальным модом будет каждый даже в этом диапазоне, нечетный в этом диапазоне, а не простые числа и т.д. Цель состояла в том, чтобы увидеть, были ли их оригинальные небольшие script выдержаны, были изменены, отлажены и обсуждены другими, и подумали ли они заранее что спецификация может измениться.

В то время как тест не сказал "в одной строке", многие взяли вызов, чтобы сделать его одной краткой линией и со стоимостью удобочитаемости. Другие сделали полный модуль, который занял слишком много времени, учитывая простую спецификацию. Наша компания должна была очень быстро реализовать твердый код; поэтому мы использовали Perl. Нам нужны программисты, которые думали одинаково.

Следующие представленные фрагменты кода делают одно и то же:

1) Too C нравится, но очень легко модифицируется. Из-за цикла аргумента

for($i=1; $i<=50; $i+=2) {
    printf("%d ", $i);
} 
print "\n";

2) Очень Perl нравится, легко получить evens, легко (с подпрограммой), чтобы получить другие циклы или шаблоны, легко понять:

print  join(' ',(grep { $_ % 2 } (1..50))), "\n"; #original
print  join(' ',(grep { !($_ % 2) } (1..50))), "\n"; #even
print  join(' ',(grep { suba($_) } (1..50))), "\n"; #other pattern

3) Слишком идиоматический, немного странный, почему он получает пробелы между результатами? Опросщик ошибся в получении эвенов. Сложнее отлаживать или читать:

print "@{[grep{$_%2}(1..50)]}\n";   #original
print "@{[grep{$_%2+1}(1..50)]}\n"; #even - WRONG!!!
print "@{[grep{~$_%2}(1..50)]}\n"; #second try for even

4) Умный! Но тоже слишком идиоматично. Подумайте о том, что происходит с хэном annon, созданным в списке операторов диапазона, и почему это создает шансы и выравнивает. Невозможно изменить на другой шаблон:

print "$_ " for (sort {$a<=>$b} keys %{{1..50}}), "\n"; #orig
print "$_ " for (sort {$a<=>$b} keys %{{2..50}}), "\n"; #even
print "$_ " for (sort {$a<=>$b} values %{{1..50}}), "\n"; #even alt

5) Kinda C нравится снова, но прочная структура. Легко модифицировать за пределы четного/нечетного. Очень читаемо:

for (1..50) { 
    print "$_ " if ($_%2); 
    }              #odd
print "\n";

for (1..50) { 
    print "$_ " unless ($_%2); 
    } #even
print "\n";

6) Возможно, мой любимый ответ. Очень Perl, как все же, читаемый (для меня в любом случае) и пошаговый в формировании и справа налево в потоке. Список справа и может быть изменен, обработка сразу слева, форматирование снова влево, окончательная операция "печать" в крайнем левом углу.

print map { "$_ " } grep { $_ & 1 } 1..50;  #original
print "\n";
print map { "$_ " } grep { !($_ & 1) } 1..50;  #even
print "\n";
print map { "$_ " } grep { suba($_) } 1..50;  #other
print "\n";

7) Это мой наименее любимый надежный ответ. Ни C, ни Perl, которые невозможно изменить без потрошения цикла, в основном показывающий, что заявитель знал синтаксис массива Perl. Он хотел, чтобы дело было действительно плохо...

for (1..50) { 
    if ($_ & 1) { 
        $odd[++$#odd]="$_ ";
        next;
    } else {    
        push @even, "$_ ";
    }
}   
print @odd, "\n";
print @even;

Опрошенные с ответами 5, 6, 2 и 1 получили работу и преуспели. Ответы 7,3,4 не наняты.

Ваш вопрос состоял в том, чтобы использовать динамические конструкции типа eval или другие, которые вы не можете сделать на чисто компилированном языке, таком как C. Этот последний пример - "динамический" с eval в регулярном выражении, но по-настоящему плохой стиль:

$t='D ' x 25;
$i=-1;
$t=~s/D/$i+=2/eg;
print "$t\n";     # don't let the door hit you on the way out...

Многие скажут вам: "Не пишите C в Perl". Я думаю, что это отчасти верно. Ошибка и ошибка в том, чтобы жестко писать новый код Perl в стиле C, даже если в Perl существует так много выразительных форм. Используйте их. И да, не пишите НОВЫЙ код Perl в стиле C, потому что синтаксис C и идиома - это все, что вы знаете. (плохая собака - без печенья)

Не записывайте динамический код в Perl только потому, что можете. Есть определенные алгоритмы, над которыми вы столкнетесь, что вы скажете: "Я не совсем понимаю, как я напишу THAT в C", и многие из них используют eval. Вы можете написать регулярное выражение Perl для анализа многих вещей (XML, HTML и т.д.) С использованием рекурсии или eval в регулярном выражении, но вы не должны этого делать. Используйте парсер так же, как и в C. Существуют определенные алгоритмы, хотя eval - подарок. Larry Wall file name fixer rename потребовалось бы намного больше C-кода для репликации, нет? Есть много других примеров.

Не допускайте жесткого ухода. Форма аргумента C 3 цикла for может быть идеально подходящей для определенных алгоритмов. Кроме того, помните, почему вы используете Perl: предположительно для высокой производительности программиста. Если у меня есть полностью отлаженный кусок кода C, который делает именно то, что я хочу, и мне это нужно в Perl, я просто переписываю глупый стиль C в Perl! Это одна из сильных сторон языка (но также и его слабость для более крупных или командных проектов, где индивидуальные стили кодирования могут варьироваться и затруднять выполнение общего кода).

До сих пор ответный ответ убийцы на этот вопрос интервью (от заявителя, написавшего ответ 6) был: Эта единственная строка кода соответствует спецификации и может быть легко изменена. Однако есть много других способов написать это. Правильный путь зависит от стиля окружающего кода, от того, как он будет называться, соображений производительности, и если формат вывода может измениться. Чувак! Когда ты можешь начать?? (Он попал в управление BTW.)

Я думаю, что отношение также относится к вашему вопросу.

Ответ 7

По крайней мере IME, "динамичный" характер на самом деле не такой большой сделки. Я думаю, что самое большое различие, которое вам нужно учесть, это то, что в C или С++ вы в основном привыкли к тому, что для использования библиотечного кода существует лишь незначительное преимущество. Что в библиотеке уже написано и отлажено, так что это удобно, но если толчок приходит в себя, вы, как правило, можете сделать почти то же самое самостоятельно. Для эффективности это в основном вопрос о том, может ли ваша способность писать что-то более специализированное, перегружает способность автора библиотеки тратить больше времени на полировку каждой рутины. Однако достаточно мало различий в том, что, если библиотечная программа действительно не делает то, что вы хотите, вам может быть лучше написать свой собственный.

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

Ответ 8

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

Ответ 9

Есть много вещей, которые вы можете сделать только с динамическим языком, но самый крутой - eval. Подробнее см. здесь.

С помощью eval вы можете выполнить строку, как если бы это была предварительно написанная команда. Вы также можете получить доступ к переменной по имени во время выполнения.

Например,

$Double = "print (\$Ord1 * 2);";

$Opd1 = 8;
eval $Double;  # Prints 8*2 =>16.

$Opd1 = 7;
eval $Double;  # Prints 7*2 =>14.

Переменная $Double является строкой, но мы можем ее выполнить, поскольку она является регулярной инструкцией. Это невозможно сделать в C/С++.

Замечательно, что во время выполнения можно манипулировать строкой; поэтому мы можем создать команду во время выполнения.

# string concatenation of operand and operator is done before eval (calculate) and then print.
$Cmd = "print (eval (\"(\$Ord1 \".\$Opr.\" \$Ord2)\"));";

$Opr  = "*";
$Ord1 = "5";
$Ord1 = "2";

eval $Cmd;  # Prints 5*2 => 10.

$Ord1 = 3;
eval $Cmd;  # Prints 5*3 => 15.

$Opr = "+";
eval $Cmd;  # Prints 5+3 => 8.

eval очень силен, поэтому (как у Человека-паука) власть несет ответственность. Используйте его с умом.

Надеюсь, что это поможет.