Beginner

Hello World in F#

Your first F# program - the classic Hello World example with Docker setup

Every programming journey starts with Hello World. Let’s write our first F# program and see how clean and expressive functional programming can be.

The Code

Create a file named hello.fsx:

1
printfn "Hello, World!"

That’s it! F# is incredibly concise. The .fsx extension indicates an F# script file that can be run directly without compilation.

Understanding the Code

  • printfn - A formatted print function that writes to the console and adds a newline
  • F# scripts - Files ending in .fsx can be run directly with F# Interactive (fsi)
  • No semicolons needed - F# is expression-oriented and whitespace-sensitive

Alternative: Compiled F# Program

If you want to create a compiled program instead of a script, create a file named Program.fs:

1
2
3
4
[<EntryPoint>]
let main argv =
    printfn "Hello, World!"
    0 // Return exit code

For beginners, the script version is simpler. For production applications, you’d use compiled .fs files.

Running with Docker

The easiest way to run F# without installing the .NET SDK locally is using Docker:

1
2
3
4
5
# Pull the official .NET SDK image
docker pull mcr.microsoft.com/dotnet/sdk:9.0

# Run the F# script
docker run --rm -v $(pwd):/app -w /app mcr.microsoft.com/dotnet/sdk:9.0 dotnet fsi hello.fsx

The dotnet fsi command runs F# Interactive, which executes your script file.

Running Locally

If you have the .NET SDK installed (version 6.0+):

For F# Scripts (.fsx):

1
2
# Run directly with F# Interactive
dotnet fsi hello.fsx

For Compiled F# Projects:

1
2
3
4
# Create a new F# console project
dotnet new console -lang F# -o HelloWorld
# Run the project
dotnet run --project HelloWorld

Expected Output

Hello, World!

Key Concepts

  1. F# is functional-first - Functions and immutability are the default approach
  2. Type inference - The compiler figures out types for you
  3. Two modes - Scripts (.fsx) for quick experimentation, compiled (.fs) for applications
  4. F# Interactive (fsi) - REPL for interactive development and testing
  5. Part of .NET - Runs on the same runtime as C# with full interoperability

F# Interactive (REPL)

F# includes a powerful REPL (Read-Eval-Print Loop) that makes exploration easy:

1
2
3
4
5
# Start F# Interactive
docker run -it --rm mcr.microsoft.com/dotnet/sdk:9.0 dotnet fsi

# Or locally:
dotnet fsi

You can type expressions and see results immediately:

1
2
3
4
5
6
7
8
> printfn "Hello, World!"
Hello, World!
> 2 + 2
val it : int = 4
> let square x = x * x
val square : x:int -> int
> square 5
val it : int = 25

This interactive development style is one of F#’s strengths!

Why printfn?

F# uses printfn instead of print because it supports printf-style formatting:

1
2
3
printfn "Hello, %s!" "World"
printfn "The answer is %d" 42
printfn "Pi is approximately %.2f" 3.14159

The f stands for “formatted,” and the n means “newline.” There’s also printf (no newline) and sprintf (returns a string).

Comparison with Other Languages

If you’re coming from other languages, here’s how F# compares:

Python:

1
print("Hello, World!")

C#:

1
Console.WriteLine("Hello, World!");

F#:

1
printfn "Hello, World!"

F# strikes a balance - concise like Python, but with the power and performance of .NET like C#.

Next Steps

Now that you’ve written your first F# program, you’re ready to explore:

  • Variables and immutability - How F# handles data
  • Functions - The heart of functional programming
  • Pattern matching - F#’s powerful control flow
  • Type inference - Writing less code while staying type-safe

F# is a language that grows with you. Start simple, and gradually discover the power of functional programming on .NET!

Running Today

All examples can be run using Docker:

docker pull mcr.microsoft.com/dotnet/sdk:9.0
Last updated: