Интерактивное программирование с помощью F #

F# Interactive (dotnet fsi) используется для интерактивного запуска кода F# в консоли или выполнения скриптов F#. Другими словами, F# Interactive выполняет команду REPL (чтение, оценка, цикл печати) для F#.

Чтобы открыть F# Interactive из консоли, запустите dotnet fsi. dotnet fsi предоставляется в любом пакете SDK для .NET.

Дополнительные сведения о доступных параметрах командной строки см. в статье Параметры F# Interactive.

Прямое выполнение кода в F# Interactive

Так как F# Interactive — это REPL (read-eval-print loop), вы можете выполнять код в этом средстве в интерактивном режиме. Ниже приведен пример интерактивного сеанса после выполнения dotnet fsi из командной строки:

Microsoft (R) F# Interactive version 11.0.0.0 for F# 5.0
Copyright (c) Microsoft Corporation. All Rights Reserved.

For help type #help;;

> let square x = x *  x;;
val square : x:int -> int

> square 12;;
val it : int = 144

> printfn "Hello, FSI!"
- ;;
Hello, FSI!
val it : unit = ()

Вы заметите две основных вещи:

  1. Весь оцениваемый код должен завершаться двумя точками с запятой (;;).
  2. Код вычисляется и сохраняется в значении it. Вы можете ссылаться на it в интерактивном режиме.

F# Interactive также поддерживает многострочный ввод. Необходимо просто указать в конце две точки с запятой (;;). Рассмотрим следующий фрагмент кода, вставленный и оцениваемый в F# Interactive:

> let getOddSquares xs =
-     xs
-     |> List.filter (fun x -> x % 2 <> 0)
-     |> List.map (fun x -> x * x)
-
- printfn "%A" (getOddSquares [1..10]);;
[1; 9; 25; 49; 81]
val getOddSquares : xs:int list -> int list
val it : unit = ()

>

Форматирование кода сохраняется, и ввод завершает две точки с запятой (;;). Затем F# Interactive оценивает код и выводит результаты.

Создание скриптов с использованием F#

Интерактивная оценка кода в F# Interactive может быть отличным средством обучения. Но вы быстро обнаружите, что это не так эффективно, как написание кода в стандартном редакторе. Чтобы использовать возможности обычного редактирования кода, можно писать скрипты F#.

Для скриптов используется расширение файла .fsx. Вместо компиляции исходного кода и последующего выполнения скомпилированной сборки можно просто запустить dotnet fsi и указать имя файла скрипта исходного кода F#, а F# Interactive считает и выполнит код в реальном времени. Например, рассмотрим следующий скрипт с именем Script.fsx:

let getOddSquares xs =
    xs
    |> List.filter (fun x -> x % 2 <> 0)
    |> List.map (fun x -> x * x)

printfn "%A" (getOddSquares [1..10])

При создании этого файла на компьютере можно запустить его с использованием dotnet fsi и просмотреть выходные данные непосредственно в окне терминала:

dotnet fsi Script.fsx
[1; 9; 25; 49; 81]

Возможность написания скриптов F# изначально поддерживается в Visual Studio, Visual Studio Code и Visual Studio для Mac.

Создание ссылок на пакеты в F# Interactive

Примечание

Система управления пакетами является расширяемой.

F# Interactive позволяет создавать ссылки на пакеты NuGet с помощью синтаксиса #r "nuget:" и дополнительной версии:

#r "nuget: Newtonsoft.Json"
open Newtonsoft.Json

let data = {| Name = "Don Syme"; Occupation = "F# Creator" |}
JsonConvert.SerializeObject(data)

Если версия не указана, используется последний доступный пакет, не являющийся предварительной версией. Чтобы создать ссылку на определенную версию, необходимо указать ее с помощью запятой. Это может быть удобно при обращении к предварительной версии пакета. Например, рассмотрим этот скрипт, используя предварительную версию DiffSharp:

#r "nuget: DiffSharp-lite, 1.0.0-preview-328097867"
open DiffSharp

// A 1D tensor
let t1 = dsharp.tensor [ 0.0 .. 0.2 .. 1.0 ]

// A 2x2 tensor
let t2 = dsharp.tensor [ [ 0; 1 ]; [ 2; 2 ] ]

// Define a scalar-to-scalar function
let f (x: Tensor) = sin (sqrt x)

printfn $"{f (dsharp.tensor 1.2)}"

Указание источника пакета

Источник пакета также можно указать с помощью команды #i. В следующем примере задаются удаленный и локальный источники:

#i "nuget: https://my-remote-package-source/index.json"
#i """nuget: C:\path\to\my\local\source"""

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

В скрипте можно указать любое количество ссылок на пакет.

Примечание

В настоящее время существует ограничение для скриптов, использующих ссылки на платформы (например Microsoft.NET.Sdk.Web , или Microsoft.NET.Sdk.WindowsDesktop ). Такие пакеты, как Saturn, Giraffe, WinForms, недоступны. Для решения создана соответствующая проблема 9417.

Создание ссылок на сборки на диске в F# Interactive

Сходным образом, если у вас есть сборка на диске и вам нужно создать ссылку на нее в скрипте, вы можете использовать синтаксис #r для указания сборки. Рассмотрим следующий код в проекте, скомпилированном в MyAssembly.dll:

// MyAssembly.fs
module MyAssembly
let myFunction x y = x + 2 * y

После компиляции можно создать ссылку в файле с именем Script.fsx следующим образом:

#r "path/to/MyAssembly.dll"

printfn $"{MyAssembly.myFunction 10 40}"

Вывод выглядит следующим образом.

dotnet fsi Script.fsx
90

В скрипте можно указать любое количество ссылок на сборку.

Загрузка других скриптов

При создании скриптов часто бывает полезно использовать разные сценарии для разных задач. Иногда может потребоваться повторно использовать код из одного скрипта в другом. Вместо копирования и вставки его содержимого в файл можно просто загрузить и оценить его с помощью #load.

Рассмотрим следующий пример с Script1.fsx:

let square x = x * x

Используемый файл Script2.fsx:

#load "Script1.fsx"
open Script1

printfn $"%d{square 12}"

Вы можете оценить Script2.fsx следующим образом:

dotnet fsi Script2.fsx
144

В скрипте можно указать любое количество директив #load.

Примечание

Обязательно необходимо объявление open Script1. Это обусловлено тем, что конструкции в скрипте F# компилируются в модуль верхнего уровня, являющийся именем файла скрипта, в котором он находится. Если файл сценария имеет имя в нижнем регистре, например script3.fsx, то имя подразумеваемого модуля автоматически пишется прописными буквами и необходимо использовать open Script3. Если вы хотите, чтобы загружаемый сценарий определял конструкции в конкретном пространстве имен или модуле, вы можете включить объявление пространства или модуля:

module MyScriptLibrary

Использование объекта fsi в коде F#

Скрипты F# имеют доступ к пользовательскому объекту fsi, который представляет сеанс F# Interactive. Это, среди прочего, позволяет настраивать форматирование вывода. Кроме того, вы можете получить доступ к аргументам командной строки.

В следующем примере показано, как получить и использовать аргументы командной строки:

let args = fsi.CommandLineArgs

for arg in args do
    printfn $"{arg}"

При оценке выводятся все аргументы. Первым аргументом всегда является имя вычисляемого скрипта:

dotnet fsi Script1.fsx hello world from fsi
Script1.fsx
hello
world
from
fsi

Кроме того, для доступа к одним и тем же аргументам вы можете использовать System.Environment.GetCommandLineArgs().

Справочник по директивам F# Interactive

Ранее упомянутые директивы #r и #load доступны только в F# Interactive. Есть несколько директив, доступных только в F# Interactive:

Директива Описание
#r "nuget:..." Ссылается на пакет из NuGet
#r "assembly-name.dll" Ссылается на сборку на диске
#load "file-name.fsx" Читает исходный файл, компилирует и запускает его.
#help Отображает сведения о доступных директивах.
#I Задает путь поиска сборок в кавычках.
#quit Завершает сеанс F# Interactive.
#time "on" или #time "off" Сама по себе директива #time позволяет включить или отключить отображение сведений о производительности. Когда она включена ("on"), F# Interactive измеряет реальное время, время ЦП и сведения о сборке мусора для каждого интерпретированного и выполненного раздела кода.

При указании файлов или путей в F# Interactive ожидается строковый литерал. Следовательно, файлы и пути должны быть заключены в кавычки; можно использовать обычные escape-символы. Кроме того, можно использовать символ @, чтобы строка, содержащая путь, интерпретировалась в F# Interactive как буквальная строка. В этом случае F# Interactive игнорирует все escape-символы.

Интерактивные и скомпилированные директивы препроцессора

При компиляции кода в F# Interactive независимо от того, запущен ли он интерактивно или с использованием скрипта, определяется символ INTERACTIVE. При компиляции кода в компиляторе определяется символ COMPILED. Таким образом, если код в режиме компиляции и интерактивном режиме должен быть разным, можно воспользоваться директивами препроцессора для условной компиляции. Это позволит определить, что именно использовать. Пример:

#if INTERACTIVE
// Some code that executes only in FSI
// ...
#endif

Использование F# Interactive в Visual Studio

Чтобы запустить F# Interactive через Visual Studio, нажмите соответствующую кнопку на панели инструментов, обозначенную F# Interactive, или используйте сочетание клавиш CTRL+ALT+F. После этого откроется интерактивное окно — окно инструментов с запущенным сеансом F# Interactive. Вы также можете выбрать код, который нужно запустить в интерактивном окне, и нажать клавиши ALT+ВВОД. F# Interactive откроется в окне инструментов F# Interactive. При использовании этого сочетания клавиш, убедитесь, что фокус находится в редактора.

Независимо от того, пользуетесь вы консолью или Visual Studio, появится командная строка и интерпретатор будет ждать ввода данных. Можно ввести код так же, как это делается в файле кода. Для компиляции и выполнения кода введите две точки с запятой (;;), чтобы разграничить одну или несколько строк входных данных.

F# Interactive попытается скомпилировать код и, в случае успеха, выполняет код и напечатает сигнатуру типов и значений, которые он скомпилировал. В случае ошибки интерпретатор напечатает сообщения об ошибке.

Код, введенный в том же сеансе имеет доступ ко всем конструкциям, введенным прежде, так что вы можете надстраивать программы. В случае необходимости благодаря значительному объему буфера в окне инструментов можно скопировать код в файл.

При запуске в Visual Studio F# Interactive работает независимо от проекта, поэтому, например, использовать определенные в проекте конструкции в F# Interactive можно, только если скопировать код функции в интерактивное окно.

Управлять аргументами (параметрами) командной строки F# Interactive можно путем корректировки значений параметров. В меню Сервис выберите пункт Параметры..., а затем разверните узел Инструменты F#. Двумя параметрами, которые можно изменить, являются параметры F# Interactive и параметр F# Interactive, 64-разрядная версия, который используется только в том случае, если F# Interactive выполняется на 64-разрядном компьютере. Этот параметр указывает, следует ли выполнять выделенную 64-разрядную версию fsi.exe или fsianycpu.exe, которая использует архитектуру компьютера для определения типа выполняемого процесса — 32- или 64-разрядного.

Заголовок Описание:
Параметры F# Interactive Описание синтаксиса команд и параметров для F# Interactive, fsi.exe.