jonnifyfsharp

Dive C1.01.3

F# Interactive

Type an expression, end it with two semicolons, and read the answer.

FSI — F# Interactive — is the language's REPL: a read-eval-print loop where you enter an expression, FSI evaluates it, and prints the value and its type. Start it from a terminal with dotnet fsi. An entry is terminated with ;;, which tells FSI to evaluate what came before; the result is printed as val it : <type> = <value>, where it names the last unnamed result. FSI is where every claim in this module can be confirmed in seconds, and it is how F# code is explored before it goes into a file.

C1.01.3 · part 1

Read, evaluate, print

FSI runs a cycle: it reads an entry, evaluates it, prints the result, and loops. The ;; terminator is the signal to evaluate — it lets an entry span several lines, so a multi-line definition is sent only when ;; closes it. An expression with no name binds to it: after 1 + 1;; prints val it : int = 2, the name it holds 2 for the next entry.

A binding prints its own name and type instead. let greet name = printfn "Hello, %s" name;; prints val greet : string -> unit — the %s format specifier requires a string, and printfn returns unit. Calling it, greet "F#";;, prints the line Hello, F# as an effect and then val it : unit = () as the result.

start FSI
dotnet fsi opens the interactive session.
terminator
;; ends an entry and triggers evaluation.
it
names the last unnamed result, available in the next entry.
val name : type
the form FSI prints — a binding's name (or it) and its type.
run a script
dotnet fsi script.fsx executes an .fsx file.

The printfn format specifiers are typed: %d for an integer, %s for a string, %f for a float, %b for a bool, and %A for any value (it prints structured data such as lists and tuples).

C1.01.3 · part 2

Directives and scripts

Beyond expressions, FSI takes directives — instructions that start with # and configure the session rather than compute a value. They load code and references, turn on timing, and control the session.

Scripts are .fsx files: ordinary F# that FSI can run top to bottom. A script can be loaded into a running session with #load, or executed in one shot from the terminal with dotnet fsi script.fsx. A package is pulled in with #r "nuget: <Package>", which fetches it from NuGet and references it, or a local assembly with #r "<path>.dll".

#load "file.fsx"          // load and run another script into the session
#r "nuget: FSharp.Data"     // reference a package from NuGet
#r "bin/MyLib.dll"       // reference a local assembly
#time "on"                 // print elapsed time + GC for each entry
#help                       // list the available directives
#quit                       // leave the session

Expressions compute; directives configure. Together they make FSI a workbench — load a script, reference a library, time a call, all without leaving the loop.

A session, one entry at a time

The transcript below is a real FSI session, replayed one entry at a time. Each step appends the input you would type and the exact line FSI prints back. The whole transcript is shown by default; the controls replay it entry by entry. Every line was captured from dotnet fsi.

The read-eval-print loop · step through a session

read an entry, ended by ;; eval run it print val it : type = value then loop, with it holding the last result
> 1 + 1;;
val it : int = 2

> let greet name = printfn "Hello, %s" name;;
val greet : string -> unit

> greet "F#";;
Hello, F#
val it : unit = ()

> [1..1000] |> List.sum;;
val it : int = 500500

> #time "on";;
--> Timing now on
entry 1 of 5 · 1 + 1 evaluates to 2, bound to it

The loop is the whole tool: read an entry, evaluate it, print the value and its type. Repeat — and reach for it to confirm anything F# can compute.

The idea

A read-eval-print loop turns the language into a workbench: ask a question, get the typed answer at once.

F# today

dotnet fsi starts the loop; [1..1000] |> List.sum;; returns val it : int = 500500 on the spot.

The floor is laid

Three dives complete the foundation. The primitive types name what a value can be and how to write it; inference gives every binding a type from its use; and FSI is the loop that prints both back, so any claim is one entry away from confirmation. With values, types, and the REPL in hand, the rest of the chapter builds upward — bindings and scope, functions and the pipeline, records and unions, pattern matching.

References

Sources

Related in this course