Первая программа на F#
Play ITЗагрузка интерактивного демо…
Первая программа на F#
Где применяют F#
F# на .NET — функциональный стиль — иммутабельность, вывод типов, |> и pattern matching при полной совместимости с C#. Data science, финтех, утилиты рядом с C# в одном solution.
Первая программа — dotnet new console -lang F#, интерактивное меню и счётчик; цикл меню построен через рекурсию и match, без классического for.
dotnet new console -lang F#
Что отработать сразу после первого запуска
- Добавьте ещё один пункт меню и отдельную функцию обработки.
- Вынесите счётчик в модуль и подключите его из
Program.fs. - Прогоните отдельные функции в FSI, чтобы видеть типы и результат без полной пересборки.
Так вы сразу переходите от "пример работает" к пониманию структуры кода и переиспользуемых частей.
Словарь терминов (перед кодом)
| Термин | Объяснение |
|---|---|
| .NET SDK | Набор инструментов: компилятор, dotnet new, dotnet run |
let | Привязать имя к значению или функции |
let mutable | Изменяемая ячейка; обновление через <- |
match ... with | Ветвление по значению и структуре данных (практикум) |
unit / () | "Ничего полезного не вернули" — тип void в F# |
rec | Рекурсивная функция (вызывает сама себя) |
printfn | Печать в консоль с переводом строки |
[<EntryPoint>] | Точка входа программы для .NET (подробнее) |
open System | Подключить пространство имён, чтобы писать Console вместо System.Console |
F# представляет собой функциональный язык программирования, работающий в среде выполнения .NET. Язык сочетает в себе мощь объектно-ориентированного подхода с парадигмой функционального программирования, позволяя описывать логику через выражения и функции. Создание первой программы демонстрирует основные принципы языка — неизменяемость данных (иммутабельность), вывод типов, работу с функциями высшего порядка и обработку списков без использования циклов. В данном материале рассматривается создание приложения "Счетчик" в консоли, использующего функциональные конструкции для управления состоянием и вывода результатов.
Создание проекта
Для начала работы требуется среда выполнения .NET SDK версии 6.0 или выше. Инструмент командной строки dotnet позволяет создавать проекты, управлять зависимостями и запускать код без необходимости установки дополнительных сред разработки.
Процесс инициализации нового проекта выполняется командой в терминале. Система автоматически создаст структуру папок, настроит файл проекта и установит необходимые библиотеки.
# Создание консольного приложения на F#
dotnet new console -lang F# -n MyFirstFSharpApp
cd MyFirstFSharpApp
# Запуск приложения
dotnet run
Блок выше создаёт шаблон консольного приложения F# (Program.fs, .fsproj). dotnet run компилирует и запускает программу в консоли.
Функциональный подход к созданию программы
В языке F# отсутствует понятие классовых методов как в Java или C#. Логика приложения организуется вокруг функций и модулей. Переменные объявляются как неизменяемые значения по умолчанию, что исключает случайное изменение состояния в процессе выполнения.
Основная логика приложения находится в файле Program.fs. Код использует оператор let для объявления значений и функций. Обработка ввода-вывода происходит через стандартные библиотеки системы ввода-вывода.
Код ITЗагрузка примера кода…
Разбор фрагмента построчно
| Строки | Что происходит |
|---|---|
open System | Доступ к Console, String из базовой библиотеки .NET |
let mutable count = 0 | Счётчик, который будем увеличивать и сбрасывать |
let displayGreeting () | Функция без аргументов; () — тип "пустой аргумент" |
String.IsNullOrEmpty name | Проверка: имя ещё не вводили |
printfn "Привет, %s! 👋" name | %s — место для строки, как в C |
inputName () | Читает строку; match input with разбирает пустой ввод и текст |
| null | "" -> | Два шаблона через | — "пустая строка или null" |
increment () | count <- count + 1 — только для mutable |
let rec mainLoop () | Меню: печать, ReadLine, match choice with |
| "2" -> increment(); mainLoop () | После действия снова вызвать меню — это и есть "цикл" |
| "5" -> ...; () | Выход: () — завершить цепочку без нового вызова mainLoop |
[<EntryPoint>] let main argv | Старт .NET; 0 — код успешного завершения |
Оператор let mutable создаёт изменяемую переменную. В учебном примере так проще показать счётчик новичку; в прикладном F# состояние часто выносят в List.fold или агентов (Асинхронность в F#: async, task и агенты).
match ... with сопоставляет строку выбора "1"…"5" с действием. Подчёркивание в ветке \| _ -> — любой другой ввод.
Рекурсивная mainLoop после каждого пункта меню вызывает сама себя — повторение без while. Базовый случай — ветка "5", где рекурсия прекращается.
Проверьте фрагменты в FSI: скопируйте displayGreeting и match на тестовых строках.
Работа с типами данных
F# обладает системой статического вывода типов. Компилятор автоматически определяет тип каждой переменной и функции на основе контекста использования. Разработчик может явно указывать типы при необходимости для улучшения читаемости кода.
// Явное указание типа
let number: int = 42
let text: string = "Привет"
let isTrue: bool = true
// Автоматический вывод типов
let age = 30 // Тип int
let message = "Hello" // Тип string
let active = true // Тип bool
Переменная number имеет тип int, так как ей присвоено целое число. Переменная text получает тип string из-за присвоенной строки. Компилятор анализирует выражения и гарантирует корректность операций. Попытка сложить строку и число вызовет ошибку компиляции, предотвращая runtime ошибки.
Функции также имеют типы. Подпись функции increment подразумевает отсутствие входных параметров (unit) и возврат единицы (unit). Функция inputName считывает строку из консоли и возвращает unit.
Обработка списков и коллекций
Одной из сильных сторон F# является работа со списками. Список — неизменяемая цепочка элементов одного типа (все int или все string). Добавление в начало не ломает старый список: создаётся новая "голова" и ссылка на прежний хвост.
[1; 2; 3]— литерал списка (элементы через;).0 :: numbers— оператор::(cons): новый список с головой0и хвостомnumbers.[1..5]— сокращение для[1; 2; 3; 4; 5](в FSI удобно проверить тип:int list).
Код ITЗагрузка примера кода…
| Выражение | Читаем по-русски |
|---|---|
List.map (fun x -> x * 2) numbers | "Для каждого x из numbers построить x*2" |
List.filter (fun x -> x > 2) numbers | "Оставить только элементы больше 2" |
List.sum numbers | "Сложить все элементы" |
(fun x -> x * 2) | Анонимная функция одного аргумента |
"%A" в printfn | Печать значения в формате отладки (удобно для списков) |
Оператор |> (конвейер) часто ставят так: numbers |> List.map ((*) 2) — "подать numbers в List.map". Читается сверху вниз.
Исходный numbers не меняется; doubledNumbers и filteredNumbers — новые списки. Так проще рассуждать о данных и писать тесты.
Модульная структура и безопасность
Программы F# часто организуются в модули. Модуль группирует связанные функции и данные. Это улучшает читаемость и поддерживает принцип инкапсуляции.
Код ITЗагрузка примера кода…
Модуль CounterModule содержит все функции, связанные со счетчиком. Переменная currentCount доступна внутри модуля. Внешний код может вызывать функции модуля, используя полное имя, например CounterModule.increment (). Это предотвращает конфликты имен и делает зависимости явными.
Расширение функционала
Полученная база служит основой для дальнейших экспериментов. Разработчики могут добавлять новые функции, изучая механизмы работы с данными и интерфейсом.
Добавление кнопки умножения счетчика на два требует объявления новой функции и подключения её к меню выбора.
let multiply () =
count <- count * 2
Ввод в цикл выбора:
| "6" -> multiply(); mainLoop ()
Создание списка задач предполагает использование рекурсии для обхода списка и фильтрации выполненных элементов.
Таймер реализуется с помощью функции System.Threading.Thread.Sleep внутри цикла, который увеличивает значение счетчика каждую секунду.
Пошаговый запуск
Для успешного запуска приложения необходимо выполнить последовательность действий.
- Установите .NET SDK 6.0+ с dotnet.microsoft.com.
- Создайте проект и перейдите в каталог:
dotnet new console -lang F# -n MyFirstFSharpApp
cd MyFirstFSharpApp
- Замените содержимое файла
Program.fsкодом примера. - Запуск:
dotnet run
Консоль отобразит меню и начнет обработку пользовательского ввода. Любые изменения в коде требуют перезапуска приложения для применения изменений.
Частые ошибки
| Симптом | Причина |
|---|---|
error FS0039 | Несовпадение имён или опечатка в let |
| "Значение не является функцией" | Лишние скобки: f x и f(x) в F# |
| Счётчик "зависает" | Рекурсия без базового случая в loop |
| Проект не собирается | Файл не в порядке компиляции .fsproj |
Что попробовать
- Перепишите счётчик через
List.foldвместо рекурсии. - Запустите фрагмент в FSI:
dotnet fsiи вставьтеletиз статьи. - Вызовите C#-библиотеку из F# — один solution, два проекта.
Дальше по курсу F#
- Интерактивная работа (FSI) — быстрые эксперименты без пересборки.
- Сопоставление с образцом — практикум — углубление
match. - Императивные конструкции — циклы,
mutable,[<EntryPoint>]. - Структура F#-проекта — несколько файлов и библиотека.
Обзор языка: F# в экосистеме .NET. Справочник: Справочник по F#.
В подборках
Статья входит в тематические подборки и блок "С чего начать?" на главной. Соседние шаги того же маршрута:
Первые шаги (маршрут подборки) — Первая программа на 1С, Первая программа на С, Первая программа на PowerShell, Первая программа на ассемблере, Первая программа на Bash, Первая программа на COBOL.