使用 F 进行交互式编程#
F# Interactive (dotnet fsi) 用于在控制台以交互方式运行 F# 代码,或执行 F# 脚本。 换句话说,F# Interactive 对 F# 执行 REPL(读取、计算、打印循环)。
若要从控制台运行 F# Interactive,请运行 dotnet fsi
。 可在任何 .NET SDK 中找到 dotnet fsi
。
注意
如果您打算在 .NET Framework 运行时下交互使用 F#,则需要安装 Visual Studio Build Tools 或 Visual Studio 版本,并FsiAnyCPU.exe
从”开发人员命令提示符“调用该命令或简单地FsiAnyCPU.exe
在PATH
环境变量中提供该命令,代替dotnet fsi
命令行。
工具支持定义版本 F# Interactive 运行时:
- 在 Visual Studio 中:在菜单栏中,工具 / 选择然后F# Tools / F# Interactive,并调整 Use .NET Core Scripting。
- 在 Visual Studio Code(ionide 扩展)中:在命令面板中,首选项:打开用户设置然后Extensions / F# / FSharp: Fsi Sdk 文档路径。
有关可用命令行选项的信息,请参阅 F# 交互式选项。
直接在 F# Interactive 中执行代码
由于 F# Interactive 是 REPL (read-eval-print 循环),因此可以在其中以交互方式执行代码。 下面是从命令行执行 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 = ()
你将注意到两个主要事项:
- 所有代码都必须以双分号(
;;
)终止以求值 - 代码计算并存储在
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# 脚本。
脚本使用 .fsxScript.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]
Visual Studio 和 Visual Studio Code 原生支持 F# 脚本。
在 F# 交互窗口中引用包
注意
包管理系统是可扩展的,请参阅有关 插件和扩展机制的详细信息。
自语言 5.0 版本发布以来,F# Interactive 支持通过扩展机制引用包;开箱即用,它可以使用以下#r "nuget:"
语法和可选版本引用 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 中正在跟踪此问题。
WinForms 仍适用于 F# Interactive 的 .NET Framework 版本。
若要在 SDK 和/或工具随附的扩展旁边加载其他扩展,请使用 --compilertool:<extensionsfolderpath>
标志作为 F# 交互式会话的参数(或在工具设置中)。
使用 F# 交互窗口引用磁盘上的程序集
或者,如果磁盘上有一个程序集并希望在脚本中引用该程序集,则可以使用 #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
在 F# 代码中使用 fsi
对象
F# 脚本有权访问表示 F# 交互式会话的自定义 fsi
对象。 它允许自定义输出格式等内容。 它还介绍了如何访问命令行参数。
以下示例演示如何获取和使用命令行参数:
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# 交互窗口指令参考
前面看到的 #r
和 #load
指令仅在 F# Interactive 中可用。 有几个指令只在 F# 交互窗口可用:
指令 | 描述 |
---|---|
#r "nuget:..." |
通过 NuGet 引用包 |
#r "extname:..." |
引用来自extname 扩展[^1] 的包(例如paket ) |
#r "assembly-name.dll" |
引用磁盘上的程序集 |
#load "file-name.fsx" |
读取源文件,对其进行编译并运行。 |
#help |
显示有关特定函数的可用指令或文档的信息。 |
#I |
用引号指定程序集搜索路径。 |
#quit |
终止 F# Interactive 会话。 |
#time on 或 #time off |
#time 本身可以切换是否显示性能信息。 在运行 on 时,F# 交互模式会测量解释和执行每段代码的实际时间、CPU 时间和垃圾回收信息。 |
[^1]:有关更多F# Interactive 扩展。
当在 F# Interactive 中指定文件或路径时,应指定字符串文本。 因此,文件和路径必须用引号引起来,也可以使用常见的转义符。 可以使用 @
字符导致 F# Interactive 将包含路径的字符串解释为逐字字符串。 这会导致 F# Interactive 忽略任何转义字符。
对于其他情况,引号是可选的,从 F# 9 开始。
扩展的#help 指令
#help
指令现在支持显示特定函数的文档。 可以直接传递函数的名称以检索详细信息。
#help List.map;;
输出如下所示:
Description:
Builds a new collection whose elements are the results of applying the given function
to each of the elements of the collection.
Parameters:
- mapping: The function to transform elements from the input list.
- list: The input list.
Returns:
The list of transformed elements.
Examples:
let inputs = [ "a"; "bbb"; "cc" ]
inputs |> List.map (fun x -> x.Length)
// Evaluates to [ 1; 3; 2 ]
Full name: Microsoft.FSharp.Collections.ListModule.map
Assembly: FSharp.Core.dll
通过此增强功能,可以更轻松地以交互方式浏览和理解 F# 库。
有关更多详细信息,请参阅 官方 devblog。
交互式预处理器指令和已编译的预处理器指令
在 F# 交互窗口中编译代码时,无论是以交互方式还是直接运行脚本,都会定义 INTERACTIVE 符号。 在编译器中编译代码时,定义了符号 COMPILED。 因此,如果代码需要在编译模式和交互式模式下不同,则可以使用这些预处理器指令进行条件编译以确定要使用的代码。 例如:
#if INTERACTIVE
// Some code that executes only in FSI
// ...
#endif
在 Visual Studio 中使用 F# Interactive
若要通过 Visual Studio 运行 F# Interactive,可以单击标记为
无论是使用控制台还是 Visual Studio,都会出现命令提示符,解释器将等待输入。 可以像在代码文件中一样输入代码。 若要编译和执行代码,请输入两个分号(;;),以终止一行或多行输入。
F# 交互尝试编译代码,如果成功,它将执行代码并输出所编译的类型和值的签名。 如果发生错误,解释器将输出错误消息。
在同一会话中输入的代码有权访问之前输入的任何构造,因此你可以构建程序。 工具窗口中的广泛缓冲区允许根据需要将代码复制到文件中。
在 Visual Studio 中运行时,F# Interactive 独立于项目运行,因此,除非将函数的代码复制到交互式窗口中,否则不能使用在 F# Interactive 项目中定义的构造。
可以通过调整设置来控制 F# Interactive 命令行参数(选项)。 在 工具 菜单上,选择 选项...,然后展开 F# 工具。 可以更改的两种设置是 F# Interactive 选项和“64 位F# Interactive”,只有在 64 位计算机上运行 F# Interactive 时,更改才有意义。 此设置确定是要运行专用 64 位版本的 fsi.exe 还是 fsianycpu.exe,该版本使用计算机体系结构来确定是作为 32 位进程还是 64 位进程运行。
相关文章
标题 | 描述 |
---|---|
F# 交互式选项 | 描述 F# Interactive (fsi.exe) 的命令行语法和选项。 |