Интерактивная работа с F# (FSI)
F# Interactive — REPL и прототипирование
В компилируемых языках обычный цикл такой: написали исходник → собрали проект (dotnet build) → запустили (dotnet run). Между правкой и результатом проходят секунды или минуты, а иногда нужно пересобрать весь solution.
F# Interactive (сокращённо FSI, от F# Interactive) — это отдельный режим: вы вводите фрагмент кода, нажимаете завершение ввода, и компилятор сразу показывает тип и значение (или текст ошибки). Такой режим называют REPL (Read–Eval–Print Loop: прочитать → вычислить → напечатать → снова ждать ввод).
FSI удобен, когда вы:
- только знакомитесь с синтаксисом F# и хотите «пощупать»
let,match, списки; - проверяете одну функцию или формулу, не создавая проект;
- смотрите, какой тип вывел компилятор (это лучший учебник по типам);
- вызываете методы из .NET (
System.DateTime,System.IO.File) и смотрите результат; - пишете одноразовый скрипт: отчёт, миграция данных, админская утилита.
Полноценное приложение с меню, конфигурацией и тестами по-прежнему живёт в .fsproj. FSI дополняет проект, а не заменяет его: сначала эксперимент в REPL, затем перенос рабочего кода в файлы библиотеки.
Предварительно: F# в экосистеме .NET · Первая программа на F#.
Словарь терминов
| Термин | Простыми словами |
|---|---|
| FSI / F# Interactive | Консольная или встроенная в IDE сессия, где код выполняется построчно |
| REPL | Интерактивная оболочка «ввод → ответ» без отдельного .exe |
Приглашение > | Строка, с которой FSI ждёт ваше выражение |
;; | Конец ввода многострочного фрагмента (две точки с запятой подряд) |
it | Имя последнего успешно вычисленного значения в сессии |
val | Строка ответа FSI: имя привязки и сигнатура типа |
Скрипт .fsx | Текстовый файл с кодом F#, который выполняет dotnet fsi |
#r, #load, #I | Директивы препроцессора скрипта: сборка, файл, каталог поиска |
Запуск FSI
Нужен установленный .NET SDK (та же версия, что и для обычных проектов F#).
В терминале:
dotnet fsi
Появится приглашение вроде:
Microsoft (R) F# Interactive version ...
For help type #help;;
>
Символ > означает: можно вводить выражение. Однострочное выражение часто достаточно завершить одной ; или Enter (зависит от оболочки); для многострочного блока в классическом FSI в конце ставят ;;:
> let square x = x * x;;
val square : int -> int
> square 7;;
val it : int = 49
Разбор ответа:
val square : int -> int— создана функцияsquare; тип читается так: «принимаетint, возвращаетint». Записьint -> int— функция одного аргумента; у функции двух аргументов будетint -> int -> int.val it : int = 49— последнее выражение дало число49; оно доступно какit(как «последний результат» в калькуляторе).
Повторный вызов:
> it + 1;;
val it : int = 50
Имя it каждый раз перезаписывается — удобно для цепочки проб, но легко запутаться, если сессия долгая.
FSI в Visual Studio и VS Code
- Visual Studio: меню View → F# Interactive или отправка выделенного кода в окно Interactive (сочетания зависят от раскладки).
- VS Code с расширением Ionide: панель F# Interactive; выделенный фрагмент отправляется в уже запущенную сессию без пересборки всего solution.
В IDE тот же компилятор F#, что и в dotnet build: правила типов и сообщения об ошибках совпадают с «боевым» проектом.
Первые шаги в REPL — что вводить
Привязка и тип
> let add x y = x + y;;
val add : int -> int -> int
Компилятор вывел типы: оба аргумента и результат — int. Если передать строку, будет ошибка несовместимости типов — это нормальная защита F#.
Списки и оператор |>
> [1..5] |> List.map ((*) 2);;
val it : int list = [2; 4; 6; 8; 10]
[1..5]— список целых от 1 до 5 включительно.|>— передача значения слева в функцию справа: «возьми список и подай его вList.map».((*) 2)— функция «умножить на 2»;(*)— оператор умножения как функция.
Такие однострочники удобно копировать потом в модуль проекта.
Подключение .NET
> open System;;
> DateTime.Now;;
val it : DateTime = ...
open System открывает пространство имён — можно писать DateTime вместо System.DateTime. FSI видит всю базовую библиотеку .NET так же, как консольное приложение.
Что проверять в REPL
| Задача | Что ввести | Зачем |
|---|---|---|
| Вывод типа | let f x y = x + y | Увидеть int -> int -> int без аннотаций |
| Ветвление | match на списке или DU | Ошибка «неполный match» видна сразу |
| Коллекции | [1..5] |> List.sum | Привыкнуть к ` |
| API библиотеки | open System.IO и вызов Path.Combine | Понять сигнатуру до переноса в проект |
| Ошибка компиляции | намеренно неверный тип | Сообщение FSxxxx указывает строку в сессии |
Интерактивный режим не ослабляет проверки: неполный match по размеченному объединению, смешение string и int — всё отлавливается до запуска .exe.
Скрипты .fsx
Файл с расширением .fsx — программа для FSI. Её не обязательно добавлять в solution; запуск:
dotnet fsi script.fsx
Пример простого скрипта:
// script.fsx
let names = [ "Anna"; "Boris"; "Chen" ]
names
|> List.map (fun n -> n.ToUpper())
|> List.iter (printfn "%s")
Строки с // — комментарии. Последняя цепочка выполнится при запуске файла.
Директивы в начале скрипта
#r "nuget: Newtonsoft.Json, 13.0.3"
#load "SharedLogic.fs"
#I @"C:\libs"
| Директива | Назначение |
|---|---|
#r "путь.dll" | Подключить уже собранную сборку |
#r "nuget: Пакет, версия" | Скачать и подключить пакет NuGet (как в проекте, но для скрипта) |
#load "File.fs" | Выполнить другой исходник F# в той же сессии (типы и функции станут видны) |
#I "каталог" | Добавить папку, где искать сборки для #r |
#help | Список директив в FSI |
#load важен для повторного использования кода: общую логику держат в .fs проекта, в скрипте подгружают тем же порядком зависимостей, что в .fsproj (см. Структура F#-проекта).
Скрипты подходят для:
- разовой выгрузки данных из CSV и записи отчёта;
- администрирования (массовое переименование, проверка API);
- обучения и демо без создания
MyTool.fsproj.
Если нужен установщик, служба Windows, публикация в Docker — лучше оформить консольный проект с dotnet publish.
REPL и проект — рекомендуемый порядок
- В FSI — набросать функцию на 5–10 строках, прогнать граничные случаи (
0, пустой список,None). - Перенести рабочий код в модуль проекта (
Domain.fs,Core.fs— см. 190). dotnet buildиdotnet test— зафиксировать поведение тестами.
Подтянуть уже существующий модуль из solution:
#load "src/MyLib/Domain.fs"
open MyLib.Domain
Порядок #load должен повторять зависимости: сначала файл с типами, потом файл, который их использует. Иначе появится ошибка «значение или пространство имён не определено» — та же логика, что и порядок <Compile Include="..."/> в .fsproj.
Состояние сессии и перезапуск
FSI накапливает все let, open и #load с начала сессии:
> let x = 1;;
> let x = 2;; // новая привязка x, старая для этого имени больше не активна
Перезапуск сессии (dotnet fsi заново или Reset в IDE) очищает память — при «странных» ошибках после множества экспериментов это первый шаг.
Повторное определение с тем же именем в проекте ведёт себя иначе, чем в REPL: в файлах .fs порядок и область видимости строго заданы компилятором.
Ограничения
- Сеть:
#r "nuget:..."при первом запуске качает пакет (нужен доступ к nuget.org, как уdotnet restore). - Долгие задачи: веб-хост ASP.NET Core, DI-контейнер, фоновые службы удобнее отлаживать в полноценном проекте с точкой останова в IDE.
- Параллелизм: эксперименты с потоками в REPL возможны, но для production-кода смотрите Асинхронность.
- Секреты: не вставляйте пароли и ключи в историю FSI на общей машине; для скриптов — переменные окружения или user secrets проекта.
Мини-практикум (5–10 минут)
- Запустите
dotnet fsi. - Определите
let twice x = x * 2и посмотрите тип. - Выполните
[1..10] |> List.filter (fun x -> x % 2 = 0) |> List.sum. - Создайте
test.fsxс#helpв комментарии и одной функцией; запуститеdotnet fsi test.fsx. - Перенесите функцию в первую программу или в отдельный
.fsпо структуре проекта.
Дальше
- Сопоставление с образцом — практикум — отрабатывайте
matchпрямо в FSI - Справочник по F# — таблицы синтаксиса
- Структура F#-проекта — порядок файлов и библиотеки
- Справочник языка F# (Learn) — официальные разделы по
async, типам, модулям
См. также
Другие статьи этого же раздела в боковом меню (как на странице «О разделе»). Платформа .NET - архитектура экосистемы, инструменты разработки и модель выполнения приложений. Эти механизмы позволили реализовать фундаментальный принцип .NET — язык — это синтаксический фасад над общей семантикой CLR. Понимание архитектуры .NET невозможно без хронологического контекста, поскольку многие текущие решения — это результат многолетней итеративной оптимизации. Типы приложений на платформе .NET - веб, desktop, мобильные и облачные сценарии в единой экосистеме. Сборка и развёртывание .NET-приложений - артефакты, среды выполнения и практики доставки в продакшен. Пакеты и зависимости в .NET - управление версиями, восстановление пакетов и интеграция в процесс сборки. В Visual Studio проект — это единица сборки — он определяет, что и как компилируется. Проект содержит .csproj, исходные файлы, ресурсы и метаданные зависимостей. NuGet - система управления пакетами .NET для публикации, версионирования и подключения зависимостей. ADO.NET в .NET 8+ — Connection, Command, параметры и провайдеры; краткая история классического ADO (COM). ASP.NET - веб-платформа Microsoft для разработки серверных приложений, API и динамических сайтов. Экосистема .NET-приложений - поддерживаемые платформы, сценарии разработки и интеграция с современными устройствами. F# в экосистеме .NET - функциональный стиль, совместимость с платформой и применение в прикладной разработке.Платформа .NET
История платформы .NET
Архитектурные особенности .NET
Типы приложений на платформе .NET
Сборка и развёртывание .NET-приложений
Пакеты и зависимости в .NET
Инструменты разработки для .NET
NuGet - система управления пакетами
ADO.NET - доступ к данным
ASP.NET - веб-платформа Microsoft
Экосистема .NET-приложений
F# - функциональный язык в экосистеме .NET