Подтвердить что ты не робот

Советы по обучению "Как мыслить функционально"?

Как новичок в функциональных языках (я начал трогать Erlang пару недель назад - первый функциональный язык, на который я мог бы справиться).

Я начал писать небольшие алгоритмы (например, left_rotate_list, bubble_sort, merge_sort и т.д.). Я часто терялся в таких решениях, как "использовать ли хелперный список для промежуточного хранилища результатов"? и "должен ли я создать вспомогательную функцию для этого?"

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

Это, по-видимому, немного противоречит дизайну OO, в котором вы можете начать снизу, чтобы построить основную структуру данных, а затем собрать структуру данных и алгоритмы в то, что вы хотите.

Спасибо за комментарии. Да, я хочу получить совет о том, как "думать в функциональном языке" (как "мышление в Java", "мышление в С++" ).

4b9b3361

Ответ 1

Через некоторое время я обнаружил, что функциональное программирование [...] поощряет проект "сверху вниз".

Я не уверен, что это точное утверждение. Недавно я пытался научить себя функциональному программированию, и я обнаружил, что мне очень помогает стиль "восходящего" программирования. Чтобы использовать пример сортировки слияния:

  • Сначала посмотрите на базовый корпус. Как вы сортируете массив из элементов 0/1?
  • Далее, посмотрите на базы + 1, base + 2,... cases. В конце концов, вы должны увидеть шаблон (расщепление на подзадачи, решение подзадач, объединение подмножеств), что позволяет вам написать общий рекурсивный случай, чем в конечном итоге достичь базового случая.
  • Расщепление на подзадачи легко, но объединение подмножеств немного сложнее. Вам нужен способ объединить два отсортированных массива в один отсортированный массив.
  • Теперь соберите все вместе. Поздравляем, вы только что создали слияние. :)

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

Ответ 2

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

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

Номер один связан с неопределенным: "элегантный код". В списках понимаются очень сжатые и математические уравнения, такие как определения функций. Просто посмотрите на быструю сортировку, выполненную с помощью LC. Вот как я определяю элегантность, лаконичность и делает все поведение понятным. Не то, что perl code-golf, где вы чаще всего кратки и загадочны.

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

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

Точно так же у некоторых изолированных племен есть только одно слово для чисел выше 3, или нет слов для "моих" / "ваших". Похоже, что у популярных языков нет слов для "это вызовет побочный эффект", но это имеет функциональное программирование. Это заставляет вас всегда знать об этом, и это хорошо.

Ответ 3

Через некоторое время я обнаружил, что функциональное программирование [...] поощряет проект "сверху вниз".

Ну, это действительно не дизайн "сверху вниз" или "снизу вверх". Это о том, чтобы сосредоточиться на "чем" проблеме, а не "как". Когда я начал с функционального программирования, я обнаружил, что я продолжал вспоминать императивные конструкции, такие как вложенный цикл for в C. Затем я быстро обнаружил, что попытка перевести мое императивное мышление на функциональные конструкции была очень сложной. Я попытаюсь дать вам более конкретный пример. Я реализую эквивалентную программу в C и Haskell и пытаюсь проследить мой мыслительный процесс в обоих случаях. Обратите внимание, что я был явно подробным для объяснения.

В C:

#include <stdio.h>

int main(void)
{
  int i, inputNumber, primeFlag = 1;
  scanf("%d", &inputNumber);
  for(i = 2; i <= inputNumber / 2; i ++)
    {
      if (inputNumber % i == 0)
        {
          primeFlag = 0;
          break;
        }
    }
  if (primeFlag == 0) printf("False\n");
  else printf ("True\n");
  return 0;
}

След моего мыслительного процесса:

  • Подумайте о шагах. Во-первых, принять номер от пользователя. Пусть это число называется inputNumber. scanf().
  • Основной алгоритм: число является простым, если не доказано иное. primeFlag объявлен и установлен равным 1.
  • Проверьте primeNumber на каждое число от 2 до primeNumber/2. Запущен цикл for. Объявлена ​​переменная цикла i для проверки primeNumber на.
  • Чтобы опровергнуть наше начальное утверждение о том, что число является простым, проверьте primeNumber на каждый i. В тот момент, когда мы найдем хотя бы один i, который делит primeNumber, установите primeFlag в 0 и break. Тело петли написано.
  • Пройдя через наш строгий процесс проверки в цикле for, проверьте значение primeFlag и сообщите об этом пользователю. printf().

В Haskell:

assertPrime :: (Integral a) => a -> Bool
assertPrime x = null divisors
    where divisors = takeWhile (<= div x 2) [y | y <- [2..], mod x y == 0]

След моего мыслительного процесса:

  • Число является простым, если у него нет делителей, кроме одного и самого. Итак, null divisors.
  • Как мы строим divisors? Во-первых, запишите список возможных кандидатов. Написал Техасский диапазон от 2 до числа /2.
  • Теперь отфильтруйте список и выберите только те элементы, которые действительно являются делителями числа. Написал фильтр mod x y == 0

Я хочу получить совет о том, как "думать в функциональном языке"

Хорошо, в первую очередь, подумайте "что", а не "как". Это может занять много практики, чтобы привыкнуть. Кроме того, если вы раньше были программистом на C/С++, как я, перестать беспокоиться о памяти! У современных языков есть сборщик мусора, и он написан для вас, поэтому не пытайтесь модифицировать переменные. Еще одна вещь, которая лично мне помогла: запишите в вашей программе английские определения, чтобы абстрагироваться от функций, выполняющих тяжелую работу.

Ответ 4

Я часто терялся в таких решениях, как "использовать ли хелперный список для промежуточного хранилища результатов"? и "должен ли я создать вспомогательную функцию для этого?"

Мой совет для этого: прочитайте The Little Schemer. Вы можете следить за ним в Эрланге. Это хорошая книга, чтобы рассказать об этом в вас.

Ответ 5

Его импорт, чтобы привыкнуть к мысли, что данные могут использоваться как код, и наоборот.

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

Через некоторое время я обнаружил, что функциональные программирование [...] поощряет "верх" вниз ".

Я согласен.