[Перевод] Зачем выбирать F#?

Если бы кто-нибудь сказал мне несколько месяцев назад, что я буду снова экспериментировать с .NET после более чем пятнадцатилетней паузы, то я бы, наверно, рассмеялся1. В начале своей карьеры я пробовал работать с .NET и Java, и хотя некоторые вещи .NET делал лучше, чем Java (у него была возможность научиться на ошибках ранней Java), я быстро остановился на Java, потому что это была по-настоящему портируемая среда.
Наверно, читающие мой блог знают, что последние несколько лет я время от времени экспериментировал с OCaml, и я могу с уверенностью сказать, что он стал одним из моих любимых языков программирования наряду с Ruby и Clojure. Недавно работа с OCaml привлекла моё внимание к F# — это разработанный компанией Microsoft ML (Meta Language) для .NET, функциональная копия объектно-ориентированного (по большей мере) C#. Самый новый ML-язык…
Что такое F#?
К сожалению, никому нельзя объяснить, что такое Матрица. Ты должен увидеть её сам.
— Морфеус, «Матрица»
Прежде, чем мы перейдём к обсуждению F#, наверно, мне нужно сначала ответить на вопрос, что же такое F#. Для ответа на него я частично процитирую официальную страницу.
F# — универсальный язык программирования для написания краткого, надёжного и высокопроизводительного кода.
F# позволяет писать чёткий самодокументирующийся код, уделяя внимание предметной области задачи, а не деталям программирования.
При этом он не жертвует скоростью и совместимостью — он кроссплатформенный, опенсорсный и функционально совместимый.
open System // Получаем доступ к функциональности в пространстве имён System.
// Определяем список имён
let names = [ "Peter"; "Julia"; "Xi" ]
// Определяем функцию, получающую имя и создающую приветствие.
let getGreeting name = $"Hello, {name}"
// Выводим приветствие для каждого имени!
names
|> List.map getGreeting
|> List.iter (fun greeting -> printfn $"{greeting}! Enjoy your F#")
Любопытный факт: F# — это язык, сделавший популярным оператор конвейера (|>).
F# обладает множеством особенностей, в том числе:
Легковесный синтаксис
Иммутабельность по умолчанию
Вывод типов и автоматическое обобщение
Функции первого класса
Мощные типы данных
Сопоставление паттернов
Асинхронное программирование
Полный список возможностей задокументирован в руководстве по языку F#.
Выглядит многообещающе, правда?
F# 1.0 был официально выпущен Microsoft Research в мае 2005 года. Изначально он разрабатывался Доном Саймом из Microsoft Research в Кембридже, развившись из раннего исследовательского проекта Caml.NET, нацеленного на перенос OCaml на платформу .NET2. В 2010 году F# официально совершил переход из Microsoft Research в Microsoft (как часть отдела инструментария для разработчиков), что совпало по времени с релизом F# 2.0.
С тех пор F# стабильно развивался, а самый новый релиз F# 9.0 был выпущен в ноябре 2024 года. F# попал в зону моего внимания в год своего двадцатилетия!
Я хотел попробовать F# по множеству причин:
Несколько лет назад .NET стал опенсорсным и портируемым, и мне хотелось оценить прогресс на этом фронте
Мне было любопытно, есть ли у F# какие-то преимущества перед OCaml
Я слышал хорошие отзывы об инструментарии F# (например, Rider и Ionide)
Я люблю играться с новыми языками программирования
Ниже я расскажу о своих первых впечатлениях в разных областях.
Язык
Это член семейства ML-языков, поэтому его синтаксис не удивит людей, знакомых с OCaml (как будто таких людей много…). Стоит отметить, что программистам на Haskell синтаксис тоже будет родным. Как и программистам на Lisp.
А всем остальным будет достаточно просто освоить базу.
// применение функции
printfn "Hello, World!"
// определение функции
let greet name =
printfn "Hello, %s!" name
greet "World"
// пробелы важны, как и в Python
let foo =
let i, j, k = (1, 2, 3)
// выражение:
i + 2 * j + 3 * k
// условные выражения
let test x y =
if x = y then "equals"
elif x < y then "is less than"
else "is greater than"
printfn "%d %s %d." 10 (test 10 20) 20
// Циклический обход списка
let list1 = [ 1; 5; 100; 450; 788 ]
for i in list1 do
printfn "%d" i
// Обход последовательности кортежей
let seq1 = seq { for i in 1 .. 10 -> (i, i*i) }
for (a, asqr) in seq1 do
printfn "%d squared is %d" a asqr
// Простой цикл for...to.
let function1 () =
for i = 1 to 10 do
printf "%d " i
printfn ""
// Цикл for...to с обратным отсчётом
let function2 () =
for i = 10 downto 1 do
printf "%d " i
printfn ""
// Записи
// Если метки определяются в одной строке, то они разделяются точкой с запятой
type Point = { X: float; Y: float; Z: float }
// Можно определять метки на отдельных строках без точки с запятой.
type Customer =
{ First: string
Last: string
SSN: uint32
AccountNumber: uint32 }
let mypoint = { X = 1.0; Y = 1.0; Z = -1.0 }
// Дизъюнктное объединение
type Shape =
| Circle of radius: float
| Rectangle of width: float * height: float
// Функция с сопоставлением паттернов
let area shape =
match shape with
| Circle radius -> System.Math.PI * radius * radius
| Rectangle (width, height) -> width * height
let circle = Circle 5.0
let rectangle = Rectangle(4.0, 3.0)
printfn "Circle area: %f" (area circle)
printfn "Rectangle area: %f" (area rectangle)
Вроде бы, ничего неожиданного?
А вот ещё один пример, чуть более сложный:
open System
// Сэмплируем данные - простые записи о продажах
type SalesRecord = { Date: DateTime; Product: string; Amount: decimal; Region: string }
// Датасет
let sales = [
{ Date = DateTime(2023, 1, 15); Product = "Laptop"; Amount = 1200m; Region = "North" }
{ Date = DateTime(2023, 2, 3); Product = "Phone"; Amount = 800m; Region = "South" }
{ Date = DateTime(2023, 1, 20); Product = "Tablet"; Amount = 400m; Region = "North" }
{ Date = DateTime(2023, 2, 18); Product = "Laptop"; Amount = 1250m; Region = "East" }
{ Date = DateTime(2023, 1, 5); Product = "Phone"; Amount = 750m; Region = "West" }
{ Date = DateTime(2023, 2, 12); Product = "Tablet"; Amount = 450m; Region = "North" }
{ Date = DateTime(2023, 1, 28); Product = "Laptop"; Amount = 1150m; Region = "South" }
]
// Конвейер быстрого анализа
let salesSummary =
sales
|> List.groupBy (fun s -> s.Product) // Группируем по товару
|> List.map (fun (product, items) -> // Преобразуем каждую группу
let totalSales = items |> List.sumBy (fun s -> s.Amount)
let avgSale = totalSales / decimal (List.length items)
let topRegion =
items
|> List.groupBy (fun s -> s.Region) // Вложенная группировка
|> List.maxBy (fun (_, regionItems) ->
regionItems |> List.sumBy (fun s -> s.Amount))
|> fst
(product, totalSales, avgSale, topRegion))
|> List.sortByDescending (fun (_, total, _, _) -> total) // Сортируем по сумме продаж
// Отображаем результаты
salesSummary
|> List.iter (fun (product, total, avg, region) ->
printfn "%s: $%M total, $%M avg, top region: %s"
product total avg region)
Можно сохранить этот код в файле Sales.fsx, и запустить его следующим образом:
dotnet fsi Sales.fsx
Теперь вы знаете, что F# — отличный выбор для написания скриптов! Кроме того, при запуске fsi dotnet откроется F# REPL, в котором можно изучать язык.
Я не буду особо вдаваться в подробности, потому что многое из того, что я писал об OCaml, применимо и к F#. Также рекомендую пройти краткий тур по F#, чтобы лучше освоить его синтаксис.
Совет: взгляните на шпаргалку по F#, если вам нужен краткий справочник по синтаксису.
На меня хорошее впечатление произвело то, что разработчики языка стремились сделать F# понятным для новичков, добавив множество мелких удобных улучшений. Ниже приведено несколько примеров, которые для вас, вероятно, будут мало значить, но их оценят люди, знакомые с OCaml:
// строчные комментарии
(* классические комментарии ML тоже присутствуют *)
// изменяемые значения
let mutable x = 5
x <- 6
// диапазоны и срезы
let l = [1..2..10]
name[5..]
// Вызовы методов C# выглядят достаточно естественно
let name = "FOO".ToLower()
// операторы можно перегружать для разных типов
let string1 = "Hello, " + "world"
let num1 = 1 + 2
let num2 = 1.0 + 2.5
// универсальный вывод
printfn "%A" [1..2..100]
Возможно, некоторые из этих аспектов могут показаться спорными пуристам ML-языков, но я считаю, что повышать популярность ML следует любыми способами.
А я говорил о том, что в языке удобно работать со строками Unicode и регулярными выражениями?
Люди часто говорят, что F# — это по большей мере полигон для будущих фич C# и возможно, это правда. Я недостаточно долго наблюдал за обоими языками, чтобы иметь собственное мнение по этой теме, но меня впечатлило, что async/await (в C#, а потом и в JavaScript) впервые появились… в F# 2.0.
Всё изменилось в 2012 году, когда был выпущен C#5, где появилась популярная пара ключевых слов async/await. Эта возможность позволяла писать код со всеми преимуществами асинхронного кода, например, отсутствием блокировки UI при запуске долговременного процесса, однако код читался, как обычный синхронный код. Этот паттерн async/await сегодня добрался до множества современных языков программирования: Python, JS, Swift, Rust и даже C++.
Подход F# к асинхронному программированию немного отличается от async/await, но решает ту же задачу (на самом деле, async/await — это урезанная версия подхода F#, появившегося несколько лет назад в F#2).
— Айзек Эйбрахам, F# in Action
Время покажет, что будет дальше, но я не думаю, что C# когда-нибудь сможет полностью заменить F#.
Кроме того, я обнаружил вдохновляющий комментарий 2022 года о том, что Microsoft, возможно, готова вкладываться больше в F#:
Хорошие новости для вас. Спустя 10 лет разработки F# двумя с половиной людьми и с приходящей время от времени помощью от сообщества, Microsoft наконец-то решила вложиться в F# и создать этим летом полнофункциональную команду в Праге. Я разработчик из этой команды; как и вы, я давний фанат F# и очень рад, что дело наконец начало двигаться.
Если посмотреть на изменения между F# 8.0 и F 9.0, то можно прийти к выводу, что полнофункциональная команда отлично справляется!
Экосистема
После столь короткого периода изучения мне сложно оценить экосистему F#, но в целом мне кажется, что существует приличное количество «нативных» библиотек и фреймворков F#, а большинство людей активно использует API core .NET и множество сторонних библиотек и фреймворков, созданных для C#. Такое достаточно часто бывает с hosted-языками, так что в этом тоже нет ничего удивительного.
Если вы когда-нибудь пользовались другим hosted-языком (например, Scala, Clojure, Groovy), то, вероятно, знаете, чего можно ожидать.
Awesome F# ведёт список популярных библиотек, инструментов и фреймворков F#. Я перечислю здесь несколько библиотек для веб-разработки и data science:
Веб-разработка
Giraffe: легковесная библиотека для создания веб-приложений с использованием ASP.NET Core. Обеспечивает функциональный подход к веб-разработке.
Suave: простая и легковесная библиотека веб-сервера с комбинаторами для маршрутизации и построения задач. (Стала источником вдохновения для разработчиков Giraffe.)
Saturn: построена на основе Giraffe и ASP.NET Core; обеспечивает фреймворк в стиле MVC, вдохновлённый Ruby on Rails и Elixir Phoenix.
Bolero: фреймворк для создания клиентских приложений на F# с использованием WebAssembly и Blazor.
Fable: компилятор, транслирующий код на F# в JavaScript, что обеспечивает интеграцию с популярными экосистемами JavaScript наподобие React и Node.js.
Elmish: архитектура model-view-update (MVU) для создания веб-UI на F#; часто используется с Fable.
SAFE Stack: сквозной стек с упором на функциональное программирование для создания веб-приложений для облаков. Сочетает в себе такие технологии, как Saturn, Azure, Fable и Elmish, обеспечивая типобезопасный процесс разработки.
Data Science
Deedle: библиотека для манипуляций с данными и исследовательского анализа, схожая с pandas для Python.
DiffSharp: библиотека для автоматического дифференцирования и машинного обучения.
FsLab: коллекция библиотек, предназначенных для data science, в том числе инструменты визуализации и работы со статистикой.
Пока я не особо экспериментировал с ними, поэтому не буду пока давать никаких отзывов и рекомендаций.
Документация
Официальная документация достаточно хороша, однако мне кажется странным, что часть её хостится на сайте Microsoft, а часть — на https://fsharp.org/ (это сайт F# Software Foundation).
Мне очень понравились следующие части документации:
F# Style Guide
F# Design — репозиторий RFC (такой должен быть у каждого языка!)
F# Standard Library API
https://fsharpforfunandprofit.com/ — это ещё один хороший ресурс для обучения (хотя ощущается немного устаревшим).
Инструментарий разработки
История инструментария разработки F# довольно непростая — раньше поддержка F# была отличной только в Visual Studio, а в других местах довольно посредственной. К счастью, за последнее десятилетие ситуация с инструментарием улучшилась:
В 2014 году произошёл технический прорыв — Томас Петричек, Райан Райли, Дейв Томас и другие последующие контрибьюторы написали пакет FSharp.Compiler.Service (FCS). В нём содержится базовая реализация компилятора F#, инструментарий редактора и скриптовый движок в виде единой библиотеки; его можно использовать для создания инструментария F# в широком спектре ситуаций. Это позволило реализовать поддержку F# во множестве других редакторов, инструментов скриптинга и документирования, а также обеспечило разработку альтернативных бэкендов F#. Основным разрабатываемым сообществом редактором стал Ionide Кшиштофа Чешлака, используемый для поддержки удобного редактирования в кроссплатформенном редакторе VSCode, на момент написания статьи скачанный более одного миллиона раз.
— Дон Сайм, The Early History of F#
Я попробовал плагины F# для различных редакторов:
Emacs (fsharp-mode)
Zed (сторонний плагин)
Helix (встроенная поддержка F#)
VS Code (Ionide)
Rider (JetBrains .NET IDE)
В целом, Rider и VS Code обладают наибольшим количеством (и качеством) возможностей, но другими вариантами тоже вполне можно пользоваться. В основном это связано с тем, что LSP-сервер F# server fsautocomplete достаточно надёжен, и любой редактор с хорошей поддержкой LSP сразу получает богатую функциональность.
Тем не менее, должен сказать, в некоторых отношениях инструментарий хромает:
fsharp-mode не использует TreeSitter (пока) и, похоже, не особо активно разрабатывается (судя по коду, он производный от caml-mode)
Поддержка F# в Zed достаточно спартанская
В VS Code, как ни странно, поломано развёртывание и сворачивание выбранного, что довольно странно, ведь он должен быть основным редактором для F#
У меня возникают серьёзные проблемы с привязками клавиш в VS Code (слишком много клавиш-модификаторов и функциональных клавиш, на мой взгляд) и моделью редактирования, поэтому в дальнейшем я, вероятно, выберу Emacs. Или наконец-то качественно разберусь с neovim!
Похоже, что все пользуются одним и тем же форматировщиком кода (Fantomas), в том числе и команда F#, что здорово! С линтером история у F# не такая хорошая (похоже, единственный популярный линтер FSharpLint ныне заброшен), но когда компилятор настолько прекрасен, линтер особо не требуется.
Выглядит так, как будто Microsoft не особо вкладывается в инструментарий F#, ведь практически все крупные проекты в этой сфере разрабатываются сообществом.
ИИ-помощники в кодинге (например, Copilot) работают с F# достаточно хорошо, но я мало их тестировал.
В конечном итоге, вероятно, подойдёт любой редактор, если вы используете LSP.
Кстати, я сделал любопытное наблюдение в процессе программирования на F# (да и на OCaml) — когда работаешь на языке с очень хорошей системой типов, то от редактора на самом деле требуется не столь многое. Чаще всего мне вполне достаточно информации об inline-типах (например, что-то типа CodeLenses), автоматического дополнения и возможности простой отправки кода в fsi. Простота по-прежнему остаётся высшей степенью утончённости…
Другие инструменты, о которых следует знать:
Paket — менеджер зависимостей для проектов .NET. Можно считать его чем-то вроде bundler, npm или pip, но для экосистемы пакетов NuGet .NET.
FAKE — DSL для создания задач и тому подобного, благодаря которому можно использовать F# для формулирования задач. Чем-то напоминает rake в Ruby. Некоторые считают его самым простым способом встраивания F# в уже существующий проект .NET.
Сценарии использования
Учитывая глубину и ширину .NET, вероятно, вас ничто не будет сдерживать!
Мне кажется, что F# особенно хорош для анализа данных и манипуляций с ними благодаря фичам наподобие поставщиков типов. Вот небольшая демонстрация работы поставщика типов JSON:
#r "nuget: FSharp.Data"
open System
open FSharp.Data
// Определяем тип на основании примера элемента JSON
type PeopleJson = JsonProvider<"""
[
{ "name": "Alice", "age": 30, "skills": ["F#", "C#", "Haskell"] }
]
""">
// Симулированный список JSON (может загружаться из файла или API)
let jsonListString = """
[
{ "name": "Alice", "age": 30, "skills": ["F#", "C#", "Haskell"] },
{ "name": "Bob", "age": 25, "skills": ["F#", "Rust"] },
{ "name": "Carol", "age": 28, "skills": ["OCaml", "Elixir"] },
{ "name": "Dave", "age": 35, "skills": ["Scala", "F#"] },
{ "name": "Eve", "age": 32, "skills": ["Python", "F#", "ML"] },
{ "name": "Frank", "age": 29, "skills": ["Clojure", "F#"] },
{ "name": "Grace", "age": 27, "skills": ["TypeScript", "Elm"] },
{ "name": "Heidi", "age": 33, "skills": ["Haskell", "PureScript"] },
{ "name": "Ivan", "age": 31, "skills": ["Racket", "F#"] },
{ "name": "Judy", "age": 26, "skills": ["ReasonML", "F#"] }
]
"""
// Парсим JSON
let people = PeopleJson.Parse(jsonListString)
// Выводим
printfn "People in the list:\n"
for p in people do
printfn "%s (age %d) knows:" p.Name p.Age
p.Skills |> Array.iter (printfn " - %s")
printfn ""
Когда я в первый раз увидел это, мне показалось это магией, ведь F# извлекает структуру и типы данных из небольшого примера данных, после чего мы получаем парсер для них. Можно сохранить код в файл TypeProvidersDemo.fsx, а потом запустить его следующим образом:
dotnet fsi TypeProvidersDemo.fsx
Более того, можно выполнять такие задачи, как извлечение данных напрямую из таблиц HTML и визуализация данных:
#r "nuget:FSharp.Data"
#r "nuget: Plotly.NET, 3.0.1"
open FSharp.Data
open Plotly.NET
type LondonBoroughs = HtmlProvider<"https://en.wikipedia.org/wiki/List_of_London_boroughs">
let boroughs = LondonBoroughs.GetSample().Tables.``List of boroughs and local authorities``
let population =
boroughs.Rows
|> Array.map (fun row ->
row.Borough,
row.``Population (2022 est)``)
|> Array.sortBy snd
|> Chart.Column
|> Chart.show
Если запустить скрипт, то в вашем браузере появится красивая диаграмма населения разных районов Лондона. Отличная штука!

Здесь стоит также отметить простоту использования внешних библиотек (например, Plotly.NET) в скриптах на F#!
Думаю, F# хорошо подойдёт для бэкенд-сервисов и даже фулстек-приложений, хоть я особо и не изучал первые решения на F# в этой сфере.
Благодаря Fable и Elmish язык F# вполне можно использовать для программирования клиентской части; к тому же они могут позволить языку F# проникнуть в вашу повседневную работу.
Примечание: в прошлом целевой платформой Fable был JavaScript, но с версии Fable 4 можно использовать и другие платформы, такие как TypeScript, Rust, Python и другие.
Вот пример того, насколько просто транспилировать кодовую базу F# на какой-нибудь другой язык:
# Транспиляция на JavaScript
dotnet fable
# Транспиляция на TypeScript
dotnet fable --lang typescript
# Транспиляция на Python
dotnet fable --lang python
Круто!
Сообщество
На первый взгляд, сообщество языка довольно маленькое, вероятно, даже меньше, чем у OCaml. Похоже, самые активные площадки для обсуждения F# — это Reddit и Discord (указанный в Reddit). Должен быть и ещё какой-то Slack по F#, но я не смог получить туда инвайта. (Кажется, автоматизированный процесс выпуска этих инвайтов уже какое-то время поломан.)
Я по-прежнему пока не очень понимаю, какую роль в сообществе играет Microsoft, потому что в целом сообщений от компании я видел не так много.
Для меня малый размер сообщества — не проблема, если оно остаётся активным и бурным. К тому же я заметил, что мне всегда были симпатичны маленькие объединения. При переходе от Java к Ruby перемена очень заметна, повышается вовлечённость в сообщество и чувство причастности.
Я не нашёл особо много книг и сайтов/блогов, посвящённых F#, но и не очень ждал этого.
Вот самые заметные общественные инициативы:
Amplifying F# — проект по продвижению F# и привлечению к нему компаний
F# for Fun and Profit — коллекция туториалов и эссе по F#
F# Lab — создаваемый сообществом инструментарий для data science на F#
F# Weekly — еженедельная рассылка о последних разработках в мире F#
Мне кажется, что для продвижения языка и привлечения новых программистов и бизнесов сделано более, чем достаточно, хоть это и всегда непросто для проекта с двадцатилетней историей. Я по-прежнему немного недоумеваю, почему Microsoft не продвигает F# активнее, ведь мне кажется, что он был бы отличным средством маркетинга.
Состязания в популярности
Люди по-разному относятся к «популярности» языков программирования. Меня часто спрашивают, почему я трачу много времени на языки, которые вряд ли принесут мне какие-то карьерные перспективы, например:
Emacs Lisp
Clojure
OCaml
F#
Возможности профессионального роста, разумеется, важны, но важно и:
развлекаться (а F в названии F# означает «fun»)
изучать новые парадигмы и идеи
бросать себе вызов, думая и работая иначе
Тем не менее, нужно отметить, что F# по большинству традиционных метрик остаётся непопулярным языком. У него не очень высокий рейтинг TIOBE, StackOverflow и на большинстве сайтов с вакансиями. Но в то же время он и не менее популярен, чем большинство «мейнстримных» функциональных языков программирования. Увы, функциональное программирование по-прежнему не мейнстримное, и, возможно, никогда таким не станет.
Ещё пара ресурсов по теме:
About F#«s popularity
How Popular is F# in 2024
Есть и видео к приведённой выше статье
F# и OCaml
Первоначальная концепция была простой F#: привнести преимущества OCaml в .NET и .NET в OCaml; создать союз между функциональным программированием со строгой типизацией и .NET. Здесь под «OCaml» подразумевается и само ядро языка, и прагматичный подход к функциональному программированию со строгой типизацией. Изначально задача была сформулирована чётко: я должен был реализовать заново ядро языка OCaml и часть его базовой библиотеки для целевой платформы .NET Common Language Runtime. Для юридической чистоты реализация должна была стать новой, то есть не использовать никакие части кодовой базы OCaml.
— Дон Сайм, создатель F#, The Early History of F#
Язык F# стал производным от OCaml, поэтому эти языки имеют много общей ДНК. На ранних этапах F# предпринимал усилия по поддержке максимально возможного объёма синтаксиса OCaml и даже позволял использовать расширения файлов .ml и .mli в коде на F#. Однако со временем пути языков начали расходиться3.
Разумеется, с самого начала рассматривалось создание языка, независимого от OCaml. Это отразилось и в выборе названия F#, хотя первые версии языка назывались Caml.NET:
Хотя первую версию F# презентовали, как «Caml для .NET», на самом деле, это всегда был новый язык, спроектированный с нуля для .NET. F# никогда не был полностью совместимым с какой-либо версией OCaml, хоть и имел общее совместимое подмножество и взял Caml-Light и OCaml за принципиальные источники вдохновения для своего дизайна.
— Дон Сайм, The Early History of F#
Если спросить у людей о плюсах и минусах F# по сравнению с OCaml, то большинство, вероятно, даст следующие ответы:
Плюсы F#
Работает на .NET
Доступна куча библиотек
Поддерживается Microsoft
Немного проще изучать новичкам (особенно тем, кто работал только с объектно-ориентированным программированием)
Немного проще разобраться в синтаксисе (мне кажется)
Ошибки и предупреждения компилятора более «дружественные» (их легче понять)
Проще отлаживать проблемы (частично связано с предыдущим пунктом)
Сильная поддержка асинхронного программирования
Имеет крутые фичи, которых нет в OCaml, например:
Анонимные записи
Активные паттерны
Вычислительные выражения
Sequence comprehension
Поставщики типов
Единицы измерения
Минусы F#
Работает на .NET
Взаимодействие с .NET повлияло на множество решений при проектировании языка (например, наличие допущения null)
Поддерживается Microsoft
Не всем нравится Microsoft
Похоже, Microsoft выделяет на F# довольно скромные ресурсы
Непонятно, насколько вовлечённой будет Microsoft в долговременной перспективе
Соглашения об именах: мне нравится snake_case гораздо больше, чем camelCase и PascalCase
Отсутствуют некоторые крутые фичи OCaml
Модули первого класса и функторы
GADT
Нет миленького логотипа с верблюдом
Название F# звучит круто, но поиск и имена файлов — это настоящий кошмар (довольно часто его называют FSharp)
И F#, и OCaml могут использовать в качестве целевой платформы среды выполнения JavaScript: F# при помощи Fable, OCaml — при помощи Js_of_ocaml и Melange. На первый взгляд Fable кажется наиболее совершенным решением, но я недостаточно долго пользовался ими тремя, чтобы моё мнение было достаточно веским.
В конечном итоге, оба остаются практически одинаково надёжными, хотя и нишевыми языками, которые вряд ли станут очень популярными в будущем. Предполагаю, что вероятность профессиональной работы с F# выше, потому что .NET очень популярен; могу представить, что можно вставлять куски F# тут и там в готовые кодовые базы на C#.
Я заметил в проектах на F# одну странную штуку — в них по-прежнему используются XML-манифесты проектов (.fsproj), в которых нужно вручную перечислять файлы исходников в порядке их компиляции (чтобы учесть зависимости между ними). Меня поразило то, что компилятор не может обрабатывать зависимости автоматически, но, думаю, дело в том, что в F# нет прямого соответствия между файлами исходников и модулями. Как бы то ни было, мне гораздо больше нравится процесс компиляции OCaml (и Dune).
Так как мой интерес к ML в основном образовательный, я склоняюсь к OCaml, но если бы мне пришлось создавать веб-сервисы на ML-языке, то я бы, вероятно, выбрал F#. Ещё я крайне уважаю все языки с собственной средой выполнения, потому что маловероятно, что среда выполнения заставит идти на какие-то компромиссы в языке.
В заключение
Вопрос: что может C# и не может F#? Ответ: NullReferenceException!
— Шутка из сообщества F#
В конечном итоге, F# мне понравится гораздо больше, чем я ожидал! В каком-то смысле он напомнил мне прежний опыт работы с Clojure в том смысле, что Clojure был самым практичным Lisp из всех выпущенных, в основном благодаря своему отличному взаимодействию с Java.
У меня есть ощущение, что если бы .NET был портируемым (и опенсорсным) изначально, то ClojureCLR, вероятно, мог бы стать столь же популярным, как и Clojure, а F#, возможно, образовал более обширное сообщество и получил больше популярности. Я уверен, что больше никогда бы не связался с .NET, если бы не .NET Core, и сомневаюсь, что я один такой. Не способствовало популярности и то, что F# не был опенсорсным до 2010 года.
Кажется, так думаю не только я:
Ошибки сложно признавать, и они лучше понятны в историческом контексте. С самого начала огромной ошибкой для F# было то, что ни .NET, ни язык не были опенсорсными и не использовали открытой разработки. Эту ошибку хорошо понимали основные контрибьюторы, и многие люди в Microsoft призывали перейти на опенсорс. Если говорить просто, инновационный язык развивался в исследовательской лаборатории компании, которая ещё не была готова принять опенсорс: участники делали всё возможное благодаря периодической публикации исходников, а в конечном итоге проблема была решена переходом на опенсорсную разработку в 2011–2014 годах. Осознание этой ошибки — вероятно, самый важный шаг в истории языка. F# способен был развиваться в 2002–2011 годах, несмотря на закрытую разработку, в основном благодаря признанию его полезных качеств ответственными лицами в Microsoft.
— Дон Сайм, The Early History of F#
Изучать OCaml точно не очень сложно, но я думаю, что людям, желающим научиться какому-нибудь диалекту ML, будет проще с F#. И, как я говорил выше, его будет проще протолкнуть в «продакшен».
Мне кажется, любой, имеющий опыт в .NET, выиграет от изучения F#. А тот, кто хочет больше использовать возможности семейства ML-языков, определённо должен задуматься о F#, это отличный язык сам по себе, дающий вам доступ к одной из самых мощных платформ программирования.
И давайте не будем забывать о Fable, благодаря которому можно использовать F# в средах выполнения JavaScript, Dart, Rust и Python!
Итак, зачем же выбирать F#? В сообществе F# есть поговорка: «F» в слове F# обозначает «Fun». Судя по моему очень кратковременному опыту работы с F#, это правда! Более того, я считаю, что F# и по-настоящему fun, и по-настоящему практичный!
Кроме того, если ваш код компилируется, то он с большой вероятностью будет работать, как задумано. Я слышал, что такое обычно приветствуется в мире программирования!
Вот и всё, что я хотел сказать.
Что дальше?
Если вам нужны другие аргументы для изучения F#, то крайне рекомендую следующие ресурсы:
F# Code I Love (доклад Дона Сайма)
Why Use F# Sharp?
Domain Modeling Made Functional
F# in Action
«The Early History of F#», которую я часто цитировал — тоже настоящее золото!
Также стоит подписаться на Reddit языка F# и присоединиться к Discord F#.
У меня были курсы по C# в университете и я написал свой диплом бакалавра на C#. Это был переписанный pacman для Arch Linux, работающий в Mono. Произошло это в 2007 году.
См. https://fsharp.org/history/hopl-final/hopl-fsharp.pdf
https://github.com/fsharp/fslang-suggestions/issues/985
Habrahabr.ru прочитано 10933 раза