.NET

индекс
121,03

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

Я думаю, что 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#.

У кого-нибудь есть такой пример?
_________
Текст подготовлен в ХабраРедакторе
+1
28 декабря 2009, 16:50
3

комментарии (30)

0
khizhaster #
У вас серьёзные проблемы с понимаем функциональных языков. Это тоже самое, что сравнивать 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
megazhuk #
Вы к кому обращаетесь? Это же перевод. Комментарий Roger'у Alsing'у можете отписать здесь.
+1
khizhaster #
мда ;( виноват
–3
Barmaleikin #
А по какому признаку в тесте вы поняли что это перевод? Я теряюсь в догадках.
+2
LeNsTR #
Слева от заголовка есть небольшой значечек, я сам еле разглядел (-: все же нагляднее когда в загаловке прописывают [перевод]
+1
Sane #
Поправил
–1
Barmaleikin #
Спасибо, а то значок этот в тупик ставит. У гугла он гораздо лучше (японская кана «а» в привычную букву «а»).
0
megazhuk #
Плюс к этому после статьи, рядом с автором перевода есть имя и ссылка на автора оригинала.
–2
Barmaleikin #
Это настолько малоприметный признак, что его можно найти только после целенаправленного поиска.
0
Sane #
Это перевод, но я в принципе согласен с автором. Единственное реальное приемущество функционального дизайна перед объектно-ориентированным — это чистота функций. Но так как F# в большей степени «sharp», чем «F», то чистоту трудно поддерживать. А с приходом контрактов в C#, писать чистые функции можно будет и на C# (ну, хотя бы подобие их). Все же остальные приемущества на самом деле уже не так актуальны — все это делается компилятором и библиотеками. У F# очень и очень узкая ниша, и ему не суждено стать mainstream.
0
KvaNTy #
«F# в большей степени «sharp», чем «F»» ушло в цитаты.

F# и не проектировался как замена С#. Пускай и не mainstream но право на жизнь у него всё-же есть.
0
Sane #
Да, это понятно. Думаю, что F# откусит большой кусок функционального программирования, благодаря IDE и .NET. Но вряд ли он появится в рабочем наборе инструментов программиста. Тем более, что C# вобрал в себя многое из функционального программирования.
0
Sane #
Да, еще Pattern matching забыл. Это, пожалуй, дейстивтельно killing feature, но у все-таки у нее очень узкая сфера применения.
0
Ai_boy #
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
Sane #
Extension everything — это, конечно, прикольно, но extension static methods — это уже перебор.

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

А вывод типов (хоть и ущербный) есть и в C#.
0
lostmsu #
Во-первых, у Вас пары параметров не хватает, а во-вторых, я своим первым постом намекал, что в си можно завести таблицы виртуальных методов, строить структуры вокруг других структур и получить OOP, в сравнении с которым С++ можно будет назвать «синтаксический сахар».

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

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

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

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

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)

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