Какие проблемы лучше или хуже решаются при функциональном программировании? - PullRequest
42 голосов
/ 16 июня 2009

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

Прежде чем я открою свою книгу по Haskell и углублюсь в функциональное программирование, я хотел бы хотя бы получить базовую идею о том, для чего я могу ее реально использовать (за пределами примеров в книге). Итак, в чем же те преимущества, в которых функциональное программирование превосходит? Для каких проблем он не подходит?

Обновление

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

Причины, по которым функциональное программирование великолепно:

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

Области, в которых борется функциональное программирование:

  • Дискуссия : веб-приложения (хотя, думаю, это будет зависеть от приложения).
  • Настольные приложения (хотя, вероятно, это зависит от языка, F # хорошо с этим справится?).
  • Всё, что критично для производительности, например, игровые движки.
  • Все, что связано с большим количеством состояний программы.

Ответы [ 11 ]

13 голосов
/ 16 июня 2009

Функциональное программирование отличается лаконичностью благодаря наличию функций более высокого уровня (map, lfold, grep) и вывода типа .

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

Я ценю эти свойства, поскольку они делают интерактивное программирование правдоподобным. (например, R , SML ).

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

11 голосов
/ 18 июня 2009

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

            Back-end   Front-end
Low-level   C          C++
High-level  FP         VB, C#
6 голосов
/ 17 июня 2009

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

F #:

type 'a stack = Cons of 'a * stack | Nil
let rec to_seq = function
    | Nil -> Seq.empty;
    | Cons(hd, tl) -> seq { yield hd; yield! to_seq tl }
let rec append x y =
    match x with
    | Nil -> y
    | Cons(hd, tl) -> Cons(hd, append tl y)
let x = Cons(1, Cons(2, Cons(3, Cons(4, Nil))))
let y = Cons(5, Cons(6, Cons(7, Cons(8, Nil))))
let z = append x y
to_seq z |> Seq.iter (fun x -> printfn "%i" x)

Java:

interface IStack<T> extends Iterable<T>
{
    IStack<T> Push(T value);
    IStack<T> Pop();
    T Peek();
    boolean IsEmpty();
}
final class EmptyStack<T> implements IStack<T>
{
    public boolean IsEmpty() { return true; }
    public IStack<T> Push(T value) { return Stack.cons(value, this); }
    public IStack<T> Pop() { throw new Error("Empty Stack"); }
    public T Peek() { throw new Error("Empty Stack"); }
    public java.util.Iterator<T> iterator()
    {
        return new java.util.Iterator<T>()
        {
            public boolean hasNext() { return false; }
            public T next() { return null; }
            public void remove() { }
        };
    }
}
final class Stack<T> implements IStack<T>
{
    public static <T> IStack<T> cons(T hd, IStack<T> tl) { return new Stack<T>(hd, tl); }
    public static <T> IStack<T> append(IStack<T> x, IStack<T> y)
    {
        return x.IsEmpty() ? y : new Stack(x.Peek(), append(x.Pop(), y));
    }
    private final T hd;
    private final IStack<T> tl;
    private Stack(T hd, IStack<T> tl)
    {
        this.hd = hd;
        this.tl = tl;
    }
    public IStack<T> Push(T value) { return new <T> Stack(value, this); }
    public IStack<T> Pop() { return this.tl; }
    public T Peek() { return this.hd; }
    public boolean IsEmpty() { return false; }
    public java.util.Iterator<T> iterator()
    {
        final IStack<T> outer = this;
        return new java.util.Iterator<T>()
        {
            private IStack<T> current = outer;
            public boolean hasNext() { return !current.IsEmpty(); }
            public T next()
            {
                T hd = current.Peek();
                current = current.Pop();
                return hd;
            }
            public void remove() { }
        };
    }
}
public class Main
{
    public static void main(String[] args)
    {
        IStack<Integer> x = Stack.cons(1, Stack.cons(2, Stack.cons(3, Stack.cons(4, new EmptyStack()))));
        IStack<Integer> y = Stack.cons(5, Stack.cons(6, Stack.cons(7, Stack.cons(8, new EmptyStack()))));
        IStack<Integer> z = Stack.append(x, y);

        for (Integer num : z)
        {
            System.out.printf("%s ", num);
        }
    }
}
6 голосов
/ 16 июня 2009

Функциональное программирование было бы хорошо для параллельного программирования. Тот факт, что вы не полагаетесь на изменения состояния при функциональном программировании, означает, что различные процессоры / ядра не будут наступать друг на друга. Таким образом, типы алгоритмов, которые хорошо подходят для параллелизма, такие как сжатие, графические эффекты и некоторые сложные математические задачи, также обычно являются хорошими кандидатами для функционального программирования. А тот факт, что популярность многоядерных и графических процессоров только растет, также означает, что спрос на подобные вещи будет расти.

4 голосов
/ 17 июня 2009

Я не согласен с тем, что FP нельзя использовать для веб-приложений. Я знаю, что Пол Грам и Роберт Моррис основали Viaweb, которая использовала Lisp для доставки веб-приложений. Я думаю, что когда вы приблизитесь к аппаратному обеспечению (драйверы устройств, ядро ​​и т. Д.), Вы захотите использовать язык как можно более низкого уровня. Это потому, что если используется больше абстракций, то в случае ошибок его сложнее отлаживать. Взгляните на статью Джоэла Спольски "Закон слабой абстракции".

4 голосов
/ 16 июня 2009

Я считаю, что Haskell хорошо подходит для выполнения любых математических задач. Не то чтобы это был настоящий профессиональный проект, но я сделал с ним решение для судоку и анализатор покера. Хорошо иметь программу, которая математически доказуема.

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

4 голосов
/ 16 июня 2009

Некоторые проблемы, для которых мне подходит функциональное программирование:

  • параллелизм
  • компиляторы
  • скриптовый

Проблемы, которые я лично считаю не очень подходящими:

  • веб-приложения (но это, вероятно, только я, например, Hacker News реализовано в LISP)
  • настольные приложения
  • игровые движки
  • вещи, где вы проходите много состояний
3 голосов
/ 19 июня 2009

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

2 голосов
/ 18 июня 2009

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

Я сказал: «есть проблемы», а не «нельзя использовать» (из-за эквивалентности по Тьюрингу все может использоваться для чего угодно).

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

2 голосов
/ 16 июня 2009

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

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