Dela via


Interaktiv programmering med F#

F# Interactive (dotnet fsi) används för att köra F#-kod interaktivt i konsolen eller för att köra F#-skript. Med andra ord kör F# interaktiv en REPL (Read, Evaluate, Print Loop) för F#.

För att köra F# Interactive från konsolen, kör dotnet fsi. Du hittar dotnet fsi i valfri .NET SDK.

Anmärkning

Om du tänker använda interaktiv F# under .NET Framework-körning behöver du Visual Studio Build Tools eller en version av Visual Studio installerad och anropa FsiAnyCPU.exe kommandot från en "Developer Command Prompt" eller helt enkelt göra FsiAnyCPU.exe det tillgängligt i PATH miljövariabeln i stället för dotnet fsi kommandoraden.

Verktygen stödjer att definiera versionen för F# Interactive runtime.

  • I Visual Studio: I menyraden, Verktygsalternativ / och sedan F# Tools / , och justera Använd .NET Core-skript.
  • I Visual Studio Code (ionide-tillägg): I kommandopaletten, Inställningar: Öppna användarinställningar och sedan Tillägg / F# / FSharp: Fsi Sdk-filsökväg.

Information om tillgängliga kommandoradsalternativ finns i Interaktiva F#-alternativ.

Köra kod direkt i F# Interactive-miljön

Eftersom F# Interactive är en REPL (read-eval-print-loop) kan du köra kod interaktivt i den. Här är ett exempel på en interaktiv session efter exekvering av dotnet fsi från kommandoraden:

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 = ()

Du kommer att märka två huvudsakliga saker:

  1. All kod måste avslutas med ett dubbelt semikolon (;;) som ska utvärderas
  2. Koden utvärderas och lagras i ett it värde. Du kan referera till it interaktivt.

F# Interactive har också stöd för indata med flera rader. Du behöver bara avsluta din sändning med ett dubbelt semikolon (;;). Överväg följande kodfragment som har klistrats in i och utvärderats av 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 = ()

>

Kodens formatering bevaras och det finns ett dubbelt semikolon (;;) som avslutar indata. F# Interactive utvärderade sedan koden och skrev ut resultatet!

Skript med F#

Att utvärdera kod interaktivt i F# Interactive kan vara ett bra inlärningsverktyg, men du kommer snabbt att upptäcka att det inte är lika produktivt som att skriva kod i en vanlig redigerare. Om du vill ha stöd för normal kodredigering kan du skriva F#-skript.

Skript använder filnamnstillägget .fsx. I stället för att kompilera källkoden och sedan köra den kompilerade sammansättningen senare kan du bara köra dotnet fsi och ange skriptets filnamn, och F# Interactive läser koden och kör den i realtid. Tänk dig till exempel följande skript med namnet Script.fsx:

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

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

När den här filen skapas på datorn kan du köra den med dotnet fsi och se utdata direkt i terminalfönstret:

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

Köra skript med en Shebang

Om du vill göra F#-skript körbara utan att dotnet fsiuttryckligen anropa kan du använda en shebang-rad överst i skriptet. På så sätt kan du köra skriptet direkt från terminalen, till exempel ett gränssnittsskript.

Skapa till exempel en skriptfil ExecutableScript.fsx med namnet med följande innehåll:

#!/usr/bin/env -S dotnet fsi

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

printfn "%A" (getOddSquares [1..10])
  1. Gör skriptet körbart:chmod Använd kommandot för att göra skriptet körbart:

    chmod +x ExecutableScript.fsx
    
  2. Kör skriptet direkt: Nu kan du köra skriptet direkt från terminalen:

    ./ExecutableScript.fsx
    

Obs! Shebang-funktioner (#!) är specifika för Unix-liknande system som Linux och MacOS. I Windows kan du köra skript med dotnet fsi Script.fsx direkt i terminalen eller kommandotolken.

Den här funktionen ger en smidigare upplevelse när du arbetar med F#-skript i miljöer som Linux och macOS.

F#-skript stöds internt i Visual Studio och Visual Studio Code.

Referera till paket i F# Interactive

Anmärkning

Pakethanteringssystemet är utökningsbart, se mer om plugin-program och tilläggsmekanismen.

Sedan version 5.0 av språket har F# Interactive stöd för att referera till paket via en utökningsmekanism. Som standard kan den referera till NuGet-paket med syntaxen #r "nuget:" och en valfri version.

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

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

Om en version inte har angetts tas det högsta tillgängliga icke-förhandsversionspaketet. Om du vill referera till en specifik version introducerar du versionen via ett kommatecken. Detta kan vara praktiskt när du refererar till en förhandsversion av ett paket. Anta till exempel att det här skriptet använder en förhandsversion av 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)}"

Som standardinställning använder #r "nuget: ...." inte byggmål från det paket som refereras till vid återställning. Alternativet usepackagetargets möjliggör användning av dessa byggmål när det behövs. Lägg bara till usepackagetargets=true om det refererade paketet skapades för att kräva det under återställningen. Exempel:

// load fsharp.data nugetpackage and consume buildtargets from fsharp.data package during restore.
#r "nuget:fsharp.data,usepackagetargets=true"
#r "nuget:fsharp.data,6.6.0,usepackagetargets=false"
#r "nuget:fsharp.data,6.6.0,usepackagetargets=true"

Ange en paketkällan

Du kan också ange en paketkälla med #i kommandot . I följande exempel anges fjärranslutna och lokala källor:

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

Detta talar om för lösningsmotorn att ta hänsyn till fjärr- och/eller lokala källor som lagts till i ett skript.

Du kan ange så många paketkällor som du vill i ett skript.

Viktigt!

Relativa sökvägar stöds för närvarande inte med #i direktivet. Du måste använda absoluta sökvägar för lokala paketkällor. Den här begränsningen spåras i dotnet/fsharp#12969.

Lösning: Du kan programmatiskt konstruera en absolut sökväg genom att använda __SOURCE_DIRECTORY__ och System.IO.Path.Combine(), och sedan använda stränginterpolation för att skicka den till direktivet #i. Till exempel:

let localSource = System.IO.Path.Combine(__SOURCE_DIRECTORY__, "relative/path/to/my/local/source")
#i $"""nuget: {localSource}"""

Anmärkning

Det finns för närvarande en begränsning för skript som använder ramverksreferenser (t.ex.Microsoft.NET.Sdk.Web eller Microsoft.NET.Sdk.WindowsDesktop). Paket som Saturnus, Giraff, WinForms är inte tillgängliga. Detta spåras i ärende #9417. WinForms fungerar fortfarande i .NET Framework-versionen av F# Interactive.

Om du vill läsa in ytterligare tillägg bredvid de som levereras med SDK:n och/eller med dina verktyg använder --compilertool:<extensionsfolderpath> du flaggan som argument för den interaktiva F#-sessionen (eller i verktygsinställningarna).

Referera till sammansättningar på disk med interaktiv F#

Om du har en sammansättning på disken och vill referera till den i ett skript kan du använda syntaxen #r för att ange en sammansättning. Överväg följande kod i ett projekt som kompilerats till MyAssembly.dll:

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

När den har kompilerats kan du referera till den i en fil som heter Script.fsx så här:

#r "path/to/MyAssembly.dll"

printfn $"{MyAssembly.myFunction 10 40}"

Utdata är följande:

dotnet fsi Script.fsx
90

Du kan ange så många sammansättningsreferenser som du vill i ett skript.

Läsa in andra skript

När du kör skript kan det ofta vara bra att använda olika skript för olika uppgifter. Ibland kanske du vill återanvända kod från ett skript i ett annat. I stället för att kopiera innehållet till filen kan du bara läsa in och utvärdera det med #load.

Tänk på följande Script1.fsx:

let square x = x * x

Och den konsumerande filen: Script2.fsx

#load "Script1.fsx"
open Script1

printfn $"%d{square 12}"

Du kan utvärdera Script2.fsx så här:

dotnet fsi Script2.fsx
144

Du kan ange så många #load direktiv som du vill i ett skript.

Anmärkning

Deklarationen open Script1 är obligatorisk. Det beror på att konstruktioner i ett F#-skript kompileras till en modul på den översta nivån som är namnet på den skriptfil som den finns i. Om skriptfilen har ett namn med liten bokstav som script3.fsx, kapitaliseras det underförstådda modulnamnet automatiskt, och då måste du använda open Script3. Om du vill att ett inläsningsbart skript ska definiera konstruktioner i ett specifikt namnområde för modulen kan du inkludera ett namnområde för moduldeklarationen, till exempel:

module MyScriptLibrary

Använda objektet fsi i F#-kod

F#-skript har åtkomst till ett anpassat fsi objekt som representerar den interaktiva F#-sessionen. Det gör att du kan anpassa saker som utdataformatering. Det är också så du kan komma åt kommandoradsargument.

I följande exempel visas hur du hämtar och använder kommandoradsargument:

let args = fsi.CommandLineArgs

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

När den utvärderas skrivs alla argument ut. Det första argumentet är alltid namnet på skriptet som utvärderas:

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

Du kan också använda System.Environment.GetCommandLineArgs() för att komma åt samma argument.

Referens för interaktivt F#-direktiv

De #r direktiv och #load som vi såg tidigare är endast tillgängliga i F# Interactive. Det finns flera direktiv som endast är tillgängliga i F# Interactive:

Direktiv Beskrivning
#r "nuget:..." Refererar till ett paket från NuGet
#r "extname:..." Referera till ett paket från extname tillägget[^1] (till exempel paket)
#r "assembly-name.dll" Refererar till en sammansättning på disk
#load "file-name.fsx" Läser en källfil, kompilerar den och kör den.
#help Visar information om tillgängliga direktiv eller dokumentation för specifika funktioner.
#I Anger en sökväg för sammansättningssökning inom citattecken.
#quit Avslutar en session i F# Interactive.
#time on eller #time off I sig #time växlar om du vill visa prestandainformation. När det är on mäter F# Interactive realtid, CPU-tid och information om skräpinsamling för varje kodavsnitt som tolkas och körs.

[^1]: Mer om interaktiva F#-tillägg.

När du anger filer eller sökvägar i F# Interactive förväntas ett strängbokstavligt uttryck. Därför måste filer och sökvägar vara inom citattecken, och de vanliga escape-tecknen gäller. Du kan använda @ tecknet för att göra så att F# Interactive tolkar en sträng som innehåller en sökväg som en ordagrann sträng. Detta gör att F# Interactive ignorerar alla escape-tecken.

I andra fall är citattecken valfria, från och med F# 9.

Utökat #help direktiv

Direktivet #help stöder nu visning av dokumentation för specifika funktioner. Du kan skicka namnet på funktionen direkt för att hämta information.

#help List.map;;

Utdata är följande:

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

Den här förbättringen gör det enklare att utforska och förstå F#-bibliotek interaktivt.

Mer information finns i den officiella devblog.

Interaktiva och kompilerade förprocessordirektiv

När du kompilerar kod i F# Interactive, oavsett om du kör interaktivt eller kör ett skript, definieras symbolen INTERACTIVE . När du kompilerar kod i kompilatorn definieras symbolen COMPILED . Om koden behöver vara annorlunda i kompilerade och interaktiva lägen kan du därför använda dessa preprocessordirektiv för villkorlig kompilering för att avgöra vilken som ska användas. Till exempel:

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

Använda F# Interactive i Visual Studio

Om du vill köra F# Interactive via Visual Studio kan du klicka på lämplig verktygsfältsknapp med etiketten F# Interactive eller använda tangenterna Ctrl+Alt+F. Om du gör detta öppnas det interaktiva fönstret, ett verktygsfönster som kör en interaktiv F#-session. Du kan också välja kod som du vill köra i det interaktiva fönstret och trycka på tangentkombinationen Alt+Retur. F# Interactive startar i ett verktygsfönster med etiketten F# Interactive. När du använder den här nyckelkombinationen kontrollerar du att redigeringsfönstret har fokus.

Oavsett om du använder konsolen eller Visual Studio visas en kommandotolk och tolken väntar på dina indata. Du kan ange kod precis som i en kodfil. Om du vill kompilera och köra koden anger du två semikolon (;;) för att avsluta en rad eller flera indatarader.

F# Interactive försöker kompilera koden och om den lyckas kör den koden och skriver ut signaturen för de typer och värden som den kompilerade. Om fel uppstår skriver tolken ut felmeddelandena.

Koden som angavs i samma session har åtkomst till alla konstruktioner som angavs tidigare, så du kan skapa program. Med en omfattande buffert i verktygsfönstret kan du kopiera koden till en fil om det behövs.

När det körs i Visual Studio körs F# Interactive oberoende av ditt projekt, så du kan till exempel inte använda konstruktioner som definierats i projektet i F# Interactive om du inte kopierar koden för funktionen till det interaktiva fönstret.

Du kan styra de interaktiva kommandoradsargumenten för F# (alternativ) genom att justera inställningarna. På menyn Verktyg väljer du Alternativ... och expanderar sedan F#-verktyg. De två inställningar som du kan ändra är de interaktiva F#-alternativen och den interaktiva inställningen 64-bitars F# som endast är relevant om du kör F# Interactive på en 64-bitars dator. Den här inställningen avgör om du vill köra den dedikerade 64-bitarsversionen av fsi.exe eller fsianycpu.exe, som använder datorarkitekturen för att avgöra om den ska köras som en 32-bitars eller 64-bitarsprocess.

Titel Beskrivning
Interaktiva F#-alternativ Beskriver kommandoradssyntax och alternativ för F# Interaktivtillståndet, fsi.exe.