[Перевод] Я все еще не просек F#

Автор оригинала: Roger Alsing
  • Перевод
Я думаю, что Microsoft пытается продать нам F# как что-то новое и крутое, но у меня серьезные проблемы с пониманием приемуществ F# перед C#.


Но F# может делать каррирование (curring) функций!
Ну, C# тоже это может.
string Foo(int a, bool b)
{
  //do stuff
}
  
void UseCurry()
{
 Func<int,string> curriedFooWithTrue = a => Foo(a,true);

 //invoke curried function.
 var res = curriedFooWithTrue(123);
}

* This source code was highlighted with Source Code Highlighter
.


F# умеет создавать конвейерные вычисления (pipelining)!
C# тоже умеет.
var listOfInts = new List<int> {1,2,3,4,5,6};
Func<int,int> squared = x => x*x;
var squaredListOfInts = listOfInts.Select(x => squared).ToList();

* This source code was highlighted with Source Code Highlighter
.

В F# есть наборы (tuples)!
Наборы встроены в .NET 4 как обобщенный тип (generic), так что они доступны во всех .NET языках, поддерживающих обобщенные типы.

В F# есть хвостовая рекурсия (tail recursion).
Хорошо, вы меня поймали, она там есть.
Но, скажите мне, когда в последний раз вам действительно она была нужна?
Любой «хвостово-рекурсивный» алгоритм может быть реализован итеративно. Но, конечно, это приятный синтаксический сахар.

В F# проще писать асинхронный код.
Это был один из аргументов на демо F# на PDC 2008.
Там было показано, как это было сделано с помощью PLinq, завернутого в сборку C#. Может, я не понял некоторых примеров, но почти каждый пример, который я видел, может быть реализован на C# приблизительно таким же объемом кода.

Что я хотел бы увидеть, так это действительно хороший пример на F#, который было бы сложно или невозможно повторить на C#.
Если F# лишь слегка лучше чем C# в некоторых задачах, то затраты на появление F# в проекте всегда будет перевешивать те небольшие приемущества, которые он сможет принести.

Другой аргумент F# в том, что он направлен на совершенно другой круг задач. Хорошо, покажите нам, где F# блистает, без обмана о том, чего может или не может C#.

У кого-нибудь есть такой пример?
Поделиться публикацией

Комментарии 30

    0
    У вас серьёзные проблемы с понимаем функциональных языков. Это тоже самое, что сравнивать LISP и C.
    Прочтите на досуге.
    ru.wikipedia.org/wiki/%D0%A4%D1%83%D0%BD%D0%BA%D1%86%D0%B8%D0%BE%D0%BD%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B5_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5
      +3
      Вы к кому обращаетесь? Это же перевод. Комментарий Roger'у Alsing'у можете отписать здесь.
        +1
        мда ;( виноват
        • НЛО прилетело и опубликовало эту надпись здесь
            +2
            Слева от заголовка есть небольшой значечек, я сам еле разглядел (-: все же нагляднее когда в загаловке прописывают [перевод]
              +1
              Поправил
              • НЛО прилетело и опубликовало эту надпись здесь
                0
                Плюс к этому после статьи, рядом с автором перевода есть имя и ссылка на автора оригинала.
                • НЛО прилетело и опубликовало эту надпись здесь
            0
            Это перевод, но я в принципе согласен с автором. Единственное реальное приемущество функционального дизайна перед объектно-ориентированным — это чистота функций. Но так как F# в большей степени «sharp», чем «F», то чистоту трудно поддерживать. А с приходом контрактов в C#, писать чистые функции можно будет и на C# (ну, хотя бы подобие их). Все же остальные приемущества на самом деле уже не так актуальны — все это делается компилятором и библиотеками. У F# очень и очень узкая ниша, и ему не суждено стать mainstream.
              0
              «F# в большей степени «sharp», чем «F»» ушло в цитаты.

              F# и не проектировался как замена С#. Пускай и не mainstream но право на жизнь у него всё-же есть.
                0
                Да, это понятно. Думаю, что F# откусит большой кусок функционального программирования, благодаря IDE и .NET. Но вряд ли он появится в рабочем наборе инструментов программиста. Тем более, что C# вобрал в себя многое из функционального программирования.
                0
                Да, еще Pattern matching забыл. Это, пожалуй, дейстивтельно killing feature, но у все-таки у нее очень узкая сфера применения.
                  0
                  1) Pattern Matching

                  2) Extension Methods, Extension Properties, Extension Static Methods, Extension Events
                  weblogs.asp.net/podwysocki/archive/2008/09/09/object-oriented-f-extension-everything.aspx

                  3) И если я не понимаю девушек это не значит что они бесполезны ;)
                    0
                    Extension everything — это, конечно, прикольно, но extension static methods — это уже перебор.

                    Целью, кстати, было, именно найти задачи, а не фичи языка. Вот одна задача — синтаксический разбор, который действительно проще делать на F#. Но когда последний раз в коммерческом проекте вы делали синтаксический разбор, для которого Regex было мало?
                      +2
                      Я на данный момент делаю синтактический разбор на C#, и мой код настолько монадичен что я подумываю об использовании F#. Правда пока только подумываю, ничего конкретного еще не сделал.
                        +1
                        Опять-таки, вы реализовали ваш проект на C#. То есть, эта не та задача, которую ищет автор.
                +3
                F# — это OCaml, достаточно качественно портированный на .net и приправленный linq и plinq технологиями. Те, кому был нужен OCaml, будут чувствовать себя уверенно, заюзав всю мощь платформы .net, включая существующие наработки. Собственно, всё.
                  +1
                  А на си можно писать в ОО-стиле. Так чем же C# лучше?
                    0
                    Писать в стиле и иметь поддержку в языке — немного разные вещи. C# имеет языковую поддержку.
                      +1
                      Так C# ведь не имеет поддержку карринга в языке.
                      Кстати, очень странно, что вы не упомянули вывод типа.
                        0
                        Поддержка карринга — это, в принципе, синтаксический сахар. Вполне можно написать набор вот таких вот функций:
                        Func<T1,Func<T2,TResult>> Curry(this Func<T1, T2, TResult> f)
                        {
                          return a=>b=>f(a,b);
                        }
                        <pre/>
                        
                        А вывод типов (хоть и ущербный) есть и в C#.
                          0
                          Во-первых, у Вас пары параметров не хватает, а во-вторых, я своим первым постом намекал, что в си можно завести таблицы виртуальных методов, строить структуры вокруг других структур и получить OOP, в сравнении с которым С++ можно будет назвать «синтаксический сахар».

                          Словом нет карринга в C#, ну нет и всё тут.
                          И пары в C# поддерживаются только через библиотеку классов.
                          И вывод типов в C# только при первом присваивании происходит.
                            0
                            Параметров — это каких? (я забыл дженерик-параметры, да) Затраты на карринг несравнимо меньше, чем для поддержанание ооп в си. Вывод типов — да, в сишарпе никакой. Пары черех библиотеку классов — так и эксепшены тоже только через библиотеку.
                    +1
                    На F# можно писать DSLи, которые очень похожи на plain old English. На C# их писать нельзя.
                      0
                      А еще есть Units of Measure… кто-нибудь помнит SIUnits и шаблонное метапрограммирование в С++? Вот-вот.
                        0
                        Да, здесь согласен. Хотя DSL по большому счету — это разбор, так что считаем это вариантом разбора.
                          0
                          External DSL — это действительно «по большому счету разбор», а Internal DSL (о котором идёт речь) почему? (Впрочем, синтаксис F#, по-моему, для IDSL подходит всё-таки существенно хуже, чем те же Ruby и Scala.)
                        0
                        Годик тому назад меня прикололи такие фитчи

                        1. Нема null по умолчанию. Парит в каждом методе писать проверку. В С# тока корявый NotNull…
                        2. Нормальные енумы. Без всякого рода меджика типа присвол инт 18…
                        3. Рекорды. Реально С# слишком уж «говорливый».
                        4. Неизменяемость по умолчанию. Это просто рулез.

                        Щас вот недавно начал копать computation expressions… Типа взял и написал свой кейворд.

                        А вообще просто по человечески язык нравиться. Значительно меньше ограничений чем в том же C#.
                          0
                          Я привёл ему пример в следующем посте:

                          F#:
                          let rec zip la lb =
                            match (la, lb) with
                            | (ha::ta), (hb::tb) -> (ha, hb) :: (zipWith func ta tb)
                            | _ -> []
                          

                          Ближайший аналог, который мне удалось получить в C#:
                          FList<Tuple<A,B>> Zip<A,B>(FList<A> la, FList<B> lb)
                          {
                          return la.Match(
                              () => FList<Tuple<A,B>>.Empty,
                              (ha, ta) => lb.Match(
                                              () => FList<Tuple<A,B>>.Empty,
                                              (hb, tb) => Tuple.New(ha, hb).Cons(Zip(la, lb))));
                          }

                          Я лично предпочту первый вариант.

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

                          F#:
                          type 'a 'b optfun = 
                            | Konst of 'b
                            | Fun of ('a -> 'b)
                          
                          ...
                          let x = Konst 0
                          

                          C#:
                          abstract public class OptFun<A,B> {
                              public sealed class Konst {
                                  B Value {get; private set;}
                                  public Konst(B value) { Value = value; }
                              }
                              public sealed class Fun {
                                  Func<A,B> Func {get; private set;}
                                  public Konst(Func<A,B> func) { Func = func; }
                              }
                          
                          // реализацию Equals, ==, !=, и GetHashCode добавьте сами
                          }
                          
                          ...
                          OptFun<int, int> x = new OptFun<int, int>.Konst(0)
                          // или в лучшем случае
                          var x = OptFun.Konst(0)
                          

                          Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                          Самое читаемое