F# Compiler Guide


Hosted Compiler

This tutorial demonstrates how to host the F# compiler.

NOTE: The FSharp.Compiler.Service API is subject to change when later versions of the nuget package are published

NOTE: There are several options for hosting the F# compiler. The easiest one is to use the fsc.exe process and pass arguments.

NOTE: By default compilations using FSharp.Compiler.Service reference FSharp.Core 4.3.0.0 (matching F# 3.0). You can override this choice by passing a reference to FSharp.Core for 4.3.1.0 or later explicitly in your command-line arguments.


First, we need to reference the libraries that contain F# interactive service:

#r "FSharp.Compiler.Service.dll"
open System.IO
open FSharp.Compiler.CodeAnalysis

// Create an interactive checker instance 
let checker = FSharpChecker.Create()

Now write content to a temporary file:

let fn = Path.GetTempFileName()
let fn2 = Path.ChangeExtension(fn, ".fsx")
let fn3 = Path.ChangeExtension(fn, ".dll")

File.WriteAllText(fn2, """
module M

type C() = 
   member x.P = 1

let x = 3 + 4
""")

Now invoke the compiler:

let errors1, exitCode1 = 
    checker.Compile([| "fsc.exe"; "-o"; fn3; "-a"; fn2 |]) 
    |> Async.RunSynchronously

If errors occur you can see this in the 'exitCode' and the returned array of errors:

File.WriteAllText(fn2, """
module M

let x = 1.0 + "" // a type error
""")

let errors1b, exitCode1b = 
    checker.Compile([| "fsc.exe"; "-o"; fn3; "-a"; fn2 |])
    |> Async.RunSynchronously

Compiling to a dynamic assembly

You can also compile to a dynamic assembly, which uses the F# Interactive code generator. This can be useful if you are, for example, in a situation where writing to the file system is not really an option.

You still have to pass the "-o" option to name the output file, but the output file is not actually written to disk.

The 'None' option indicates that the initialization code for the assembly is not executed.

let errors2, exitCode2, dynAssembly2 = 
    checker.CompileToDynamicAssembly([| "-o"; fn3; "-a"; fn2 |], execute=None)
     |> Async.RunSynchronously

(*
Passing 'Some' for the 'execute' parameter executes  the initialization code for the assembly.
*)
let errors3, exitCode3, dynAssembly3 = 
    checker.CompileToDynamicAssembly([| "-o"; fn3; "-a"; fn2 |], Some(stdout,stderr))
     |> Async.RunSynchronously
namespace System
namespace System.IO
Multiple items
namespace FSharp

--------------------
namespace Microsoft.FSharp
namespace FSharp.Compiler
namespace FSharp.Compiler.CodeAnalysis
val checker : FSharpChecker
type FSharpChecker = member CheckFileInProject : parseResults:FSharpParseFileResults * fileName:string * fileVersion:int * sourceText:ISourceText * options:FSharpProjectOptions * ?userOpName:string -> Async<FSharpCheckFileAnswer> member ClearCache : options:seq<FSharpProjectOptions> * ?userOpName:string -> unit member ClearLanguageServiceRootCachesAndCollectAndFinalizeAllTransients : unit -> unit member Compile : argv:string [] * ?userOpName:string -> Async<FSharpDiagnostic [] * int> + 1 overload member CompileToDynamicAssembly : otherFlags:string [] * execute:(TextWriter * TextWriter) option * ?userOpName:string -> Async<FSharpDiagnostic [] * int * Assembly option> + 1 overload member FindBackgroundReferencesInFile : fileName:string * options:FSharpProjectOptions * symbol:FSharpSymbol * ?canInvalidateProject:bool * ?userOpName:string -> Async<seq<range>> member GetBackgroundCheckResultsForFileInProject : fileName:string * options:FSharpProjectOptions * ?userOpName:string -> Async<FSharpParseFileResults * FSharpCheckFileResults> member GetBackgroundParseResultsForFileInProject : fileName:string * options:FSharpProjectOptions * ?userOpName:string -> Async<FSharpParseFileResults> member GetBackgroundSemanticClassificationForFile : fileName:string * options:FSharpProjectOptions * ?userOpName:string -> Async<SemanticClassificationView option> member GetParsingOptionsFromCommandLineArgs : sourceFiles:string list * argv:string list * ?isInteractive:bool * ?isEditing:bool -> FSharpParsingOptions * FSharpDiagnostic list + 1 overload ...
<summary> Used to parse and check F# source code. </summary>
static member FSharpChecker.Create : ?projectCacheSize:int * ?keepAssemblyContents:bool * ?keepAllBackgroundResolutions:bool * ?legacyReferenceResolver:LegacyReferenceResolver * ?tryGetMetadataSnapshot:FSharp.Compiler.AbstractIL.ILBinaryReader.ILReaderTryGetMetadataSnapshot * ?suggestNamesForErrors:bool * ?keepAllBackgroundSymbolUses:bool * ?enableBackgroundItemKeyStoreAndSemanticClassification:bool * ?enablePartialTypeChecking:bool -> FSharpChecker
val fn : string
type Path = static member ChangeExtension : path: string * extension: string -> string static member Combine : path1: string * path2: string -> string + 3 overloads static member EndsInDirectorySeparator : path: ReadOnlySpan<char> -> bool + 1 overload static member GetDirectoryName : path: ReadOnlySpan<char> -> ReadOnlySpan<char> + 1 overload static member GetExtension : path: ReadOnlySpan<char> -> ReadOnlySpan<char> + 1 overload static member GetFileName : path: ReadOnlySpan<char> -> ReadOnlySpan<char> + 1 overload static member GetFileNameWithoutExtension : path: ReadOnlySpan<char> -> ReadOnlySpan<char> + 1 overload static member GetFullPath : path: string -> string + 1 overload static member GetInvalidFileNameChars : unit -> char [] static member GetInvalidPathChars : unit -> char [] ...
<summary>Performs operations on <see cref="T:System.String" /> instances that contain file or directory path information. These operations are performed in a cross-platform manner.</summary>
Path.GetTempFileName() : string
val fn2 : string
Path.ChangeExtension(path: string, extension: string) : string
val fn3 : string
type File = static member AppendAllLines : path: string * contents: IEnumerable<string> -> unit + 1 overload static member AppendAllLinesAsync : path: string * contents: IEnumerable<string> * encoding: Encoding *?cancellationToken: CancellationToken -> Task + 1 overload static member AppendAllText : path: string * contents: string -> unit + 1 overload static member AppendAllTextAsync : path: string * contents: string * encoding: Encoding *?cancellationToken: CancellationToken -> Task + 1 overload static member AppendText : path: string -> StreamWriter static member Copy : sourceFileName: string * destFileName: string -> unit + 1 overload static member Create : path: string -> FileStream + 2 overloads static member CreateText : path: string -> StreamWriter static member Decrypt : path: string -> unit static member Delete : path: string -> unit ...
<summary>Provides static methods for the creation, copying, deletion, moving, and opening of a single file, and aids in the creation of <see cref="T:System.IO.FileStream" /> objects.</summary>
File.WriteAllText(path: string, contents: string) : unit
File.WriteAllText(path: string, contents: string, encoding: System.Text.Encoding) : unit
val errors1 : FSharp.Compiler.Diagnostics.FSharpDiagnostic []
val exitCode1 : int
member FSharpChecker.Compile : argv:string [] * ?userOpName:string -> Async<FSharp.Compiler.Diagnostics.FSharpDiagnostic [] * int>
member FSharpChecker.Compile : ast:FSharp.Compiler.Syntax.ParsedInput list * assemblyName:string * outFile:string * dependencies:string list * ?pdbFile:string * ?executable:bool * ?noframework:bool * ?userOpName:string -> Async<FSharp.Compiler.Diagnostics.FSharpDiagnostic [] * int>
Multiple items
type Async = static member AsBeginEnd : computation:('Arg -> Async<'T>) -> ('Arg * AsyncCallback * obj -> IAsyncResult) * (IAsyncResult -> 'T) * (IAsyncResult -> unit) static member AwaitEvent : event:IEvent<'Del,'T> * ?cancelAction:(unit -> unit) -> Async<'T> (requires delegate and 'Del :> Delegate) static member AwaitIAsyncResult : iar:IAsyncResult * ?millisecondsTimeout:int -> Async<bool> static member AwaitTask : task:Task<'T> -> Async<'T> + 1 overload static member AwaitWaitHandle : waitHandle:WaitHandle * ?millisecondsTimeout:int -> Async<bool> static member CancelDefaultToken : unit -> unit static member Catch : computation:Async<'T> -> Async<Choice<'T,exn>> static member Choice : computations:seq<Async<'T option>> -> Async<'T option> static member FromBeginEnd : beginAction:(AsyncCallback * obj -> IAsyncResult) * endAction:(IAsyncResult -> 'T) * ?cancelAction:(unit -> unit) -> Async<'T> + 3 overloads static member FromContinuations : callback:(('T -> unit) * (exn -> unit) * (OperationCanceledException -> unit) -> unit) -> Async<'T> ...
<summary>Holds static members for creating and manipulating asynchronous computations.</summary>
<remarks> See also <a href="https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/asynchronous-workflows">F# Language Guide - Async Workflows</a>. </remarks>
<category index="1">Async Programming</category>


--------------------
type Async<'T> =
<summary> An asynchronous computation, which, when run, will eventually produce a value of type T, or else raises an exception. </summary>
<remarks> This type has no members. Asynchronous computations are normally specified either by using an async expression or the static methods in the <see cref="T:Microsoft.FSharp.Control.Async" /> type. See also <a href="https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/asynchronous-workflows">F# Language Guide - Async Workflows</a>. </remarks>
<namespacedoc><summary> Library functionality for asynchronous programming, events and agents. See also <a href="https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/asynchronous-workflows">Asynchronous Programming</a>, <a href="https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/members/events">Events</a> and <a href="https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/lazy-expressions">Lazy Expressions</a> in the F# Language Guide. </summary></namespacedoc>
<category index="1">Async Programming</category>
static member Async.RunSynchronously : computation:Async<'T> * ?timeout:int * ?cancellationToken:System.Threading.CancellationToken -> 'T
val errors1b : FSharp.Compiler.Diagnostics.FSharpDiagnostic []
val exitCode1b : int
val errors2 : FSharp.Compiler.Diagnostics.FSharpDiagnostic []
val exitCode2 : int
val dynAssembly2 : System.Reflection.Assembly option
member FSharpChecker.CompileToDynamicAssembly : otherFlags:string [] * execute:(TextWriter * TextWriter) option * ?userOpName:string -> Async<FSharp.Compiler.Diagnostics.FSharpDiagnostic [] * int * System.Reflection.Assembly option>
member FSharpChecker.CompileToDynamicAssembly : ast:FSharp.Compiler.Syntax.ParsedInput list * assemblyName:string * dependencies:string list * execute:(TextWriter * TextWriter) option * ?debug:bool * ?noframework:bool * ?userOpName:string -> Async<FSharp.Compiler.Diagnostics.FSharpDiagnostic [] * int * System.Reflection.Assembly option>
union case Option.None: Option<'T>
<summary>The representation of "No value"</summary>
val errors3 : FSharp.Compiler.Diagnostics.FSharpDiagnostic []
val exitCode3 : int
val dynAssembly3 : System.Reflection.Assembly option
union case Option.Some: Value: 'T -> Option<'T>
<summary>The representation of "Value of type 'T"</summary>
<param name="Value">The input value.</param>
<returns>An option representing the value.</returns>
val stdout<'T> : TextWriter
<summary>Reads the value of the property <see cref="P:System.Console.Out" />.</summary>
val stderr<'T> : TextWriter
<summary>Reads the value of the property <see cref="P:System.Console.Error" />. </summary>