Перейти к основному содержимому

Первая программа на 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 внутри цикла, который увеличивает значение счетчика каждую секунду.


Пошаговый запуск

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

  1. Установите .NET SDK 6.0+ с dotnet.microsoft.com.
  2. Создайте проект и перейдите в каталог:
dotnet new console -lang F# -n MyFirstFSharpApp
cd MyFirstFSharpApp
  1. Замените содержимое файла Program.fs кодом примера.
  2. Запуск:
dotnet run

Консоль отобразит меню и начнет обработку пользовательского ввода. Любые изменения в коде требуют перезапуска приложения для применения изменений.


Частые ошибки

СимптомПричина
error FS0039Несовпадение имён или опечатка в let
"Значение не является функцией"Лишние скобки: f x и f(x) в F#
Счётчик "зависает"Рекурсия без базового случая в loop
Проект не собираетсяФайл не в порядке компиляции .fsproj

Что попробовать

  1. Перепишите счётчик через List.fold вместо рекурсии.
  2. Запустите фрагмент в FSI: dotnet fsi и вставьте let из статьи.
  3. Вызовите C#-библиотеку из F# — один solution, два проекта.

Дальше по курсу F#

  1. Интерактивная работа (FSI) — быстрые эксперименты без пересборки.
  2. Сопоставление с образцом — практикум — углубление match.
  3. Императивные конструкции — циклы, mutable, [<EntryPoint>].
  4. Структура F#-проекта — несколько файлов и библиотека.

Обзор языка: F# в экосистеме .NET. Справочник: Справочник по F#.


В подборках

Статья входит в тематические подборки и блок "С чего начать?" на главной. Соседние шаги того же маршрута:

Первые шаги (маршрут подборки) — Первая программа на 1С, Первая программа на С, Первая программа на PowerShell, Первая программа на ассемблере, Первая программа на Bash, Первая программа на COBOL.