Guide 11 aprile 2026 | 13 min di lettura

Come Iniziare con F# in 15 Passi: Guida Completa per Principianti

Scopri F#, il linguaggio funzionale-first di Microsoft per .NET. Tutorial passo-passo con installazione, setup Visual Studio Code/Visual Studio, esempi pratici, troubleshooting e confronto con C#. Perfetto per chi inizia!

computer con una scritta f# e un 1

F# è un linguaggio general-purpose, high-level, fortemente tipizzato e multi-paradigma che include programmazione funzionale, imperativa e orientata agli oggetti. Il linguaggio è stato originariamente progettato e implementato da Don Syme; all’interno del team F# dicono che la “F” sta per “Fun”.

Se vieni dal mondo C# o Java, preparati a un cambio di mentalità: F# supporta ben tre paradigmi di programmazione: funzionale, imperativo e orientato agli oggetti. A differenza dei linguaggi OOP classici, in F# “tutto è una funzione”, proprio come in un linguaggio object-oriented “tutto è un oggetto”.

F# semplifica la scrittura di codice conciso, affidabile ed efficiente. Imparerai a scrivere programmi più robusti, con meno bug e in meno righe di codice. Alla fine di questo tutorial avrai configurato il tuo ambiente di sviluppo, scritto le tue prime funzioni F#, compreso l’inferenza di tipo e padroneggiato le basi della programmazione funzionale su .NET.

Prerequisiti

Prima di iniziare, devi avere familiarità con i concetti base della programmazione: sapere cosa sono le variabili, le funzioni, i loop e i tipi di dato. Non serve esperienza in programmazione funzionale anzi, questo tutorial è pensato proprio per chi parte da zero con F#.

Se conosci C# o un altro linguaggio .NET, ottimo: molti concetti ti saranno già familiari. Ma attenzione: per riuscire a programmare in F# serve un cambiamento nell’approccio mentale, perché passare da un paradigma a un altro è sempre difficile.

Strumenti necessari

Per seguire il tutorial ti servono:

  • .NET SDK: Il .NET SDK è un ambiente di sviluppo software usato per sviluppare applicazioni .NET. Scaricalo dal sito ufficiale Microsoft (versione 8.0 o superiore consigliata).
  • Editor o IDE: puoi scegliere Visual Studio Code (gratuito, multipiattaforma) oppure Visual Studio 2019/2022 (anche l’edizione Community gratuita va benissimo).
  • Ionide (per VS Code): Puoi scrivere F# in Visual Studio Code con il plugin Ionide per ottenere un’esperienza IDE cross-platform leggera con IntelliSense e refactoring del codice.

Passo-passo

Step 1 — Installare .NET SDK

Il primo passo è installare il .NET SDK sul tuo sistema operativo. Vai su https://dotnet.microsoft.com/download e scarica l’ultima versione stabile dell’SDK.

Dopo l’installazione, apri il terminale (o PowerShell su Windows) e verifica che tutto funzioni:

dotnet --version

Dovresti vedere il numero di versione del SDK installato (es. 8.0.100). Se il comando non viene riconosciuto, riavvia il terminale o verifica che il PATH sia configurato correttamente.

Suggerimento: Su Windows, potrebbe essere necessario riavviare il computer per aggiornare le variabili d’ambiente.

Step 2 — Scegliere e configurare l’editor

Opzione A: Visual Studio Code

Visual Studio Code è un editor di codice sorgente gratuito, open source e cross-platform che supporta molti linguaggi. F# è supportato dal progetto Ionide.

  1. Scarica e installa VS Code
  2. L’unico plugin richiesto per il supporto F# in Visual Studio Code è Ionide-fsharp. Apri VS Code, vai alla sezione Estensioni (Ctrl+Shift+X) e cerca “Ionide-fsharp”. Installa l’estensione.
  3. Opzionalmente, installa anche “Ionide-FAKE” e “Ionide-Paket” per funzionalità di build e gestione dipendenze.

Opzione B: Visual Studio

Se preferisci un IDE completo:

  1. Se scarichi Visual Studio per la prima volta, verrà prima installato il Programma di installazione di Visual Studio. Installa l’edizione appropriata di Visual Studio dal programma di installazione.
  2. Nella pagina Carichi di lavoro seleziona il carico di lavoro “ASP.NET e sviluppo Web”, che include il supporto di F# e .NET Core per i progetti ASP.NET Core.
  3. Clicca “Modifica” e attendi l’installazione.

Step 3 — Creare il primo progetto F#

Usiamo il .NET CLI per creare un progetto console:

dotnet new console -lang "F#" -o HelloFSharp
cd HelloFSharp

Questo comando crea una nuova directory HelloFSharp con un progetto console F# preconfigurato. All’interno trovi:

  • Program.fs — il file sorgente principale
  • HelloFSharp.fsproj — il file di progetto

Apri la cartella in VS Code (code .) o Visual Studio.

Step 4 — Esplorare il codice generato

Apri Program.fs. Dovresti vedere qualcosa del genere:

open System

[<EntryPoint>]
let main argv =
    printfn "Hello from F#!"
    0 // return an integer exit code

Anatomia del codice:

  • open System — equivalente a using in C#, importa lo spazio dei nomi System
  • [<EntryPoint>] — attributo che indica il punto di ingresso del programma
  • let main argv = — definisce la funzione main che riceve gli argomenti da riga di comando
  • printfn — stampa una stringa seguita da newline
  • 0 — valore di ritorno (exit code)

Nota: F# è un linguaggio poco verboso, molto espressivo e conciso. Non ama i fronzoli, preferisce l’essenza. Non ci sono parentesi graffe né punti e virgola!

Step 5 — Eseguire il programma

Dal terminale, nella directory del progetto, esegui:

dotnet run

Dovresti vedere l’output:

Hello from F#!

Congratulazioni! Hai appena eseguito il tuo primo programma F#.

Step 6 — Capire l’immutabilità e il binding con let

In F#, quando assegniamo a una “variabile” un valore, questa “variabile” è immutabile nel tempo. Le assegnazioni si fanno usando let.

Modifica Program.fs:

let x = 42
printfn "Il valore di x è: %d" x

let nome = "Alice"
printfn "Ciao, %s!" nome

In F#, x e nome non sono “variabili” nel senso tradizionale, ma identificatori immutabili. Una volta assegnati, non possono essere riassegnati.

Nota: Se vuoi davvero una variabile mutabile, puoi usare mutable:

let mutable contatore = 0
contatore <- contatore + 1
printfn "Contatore: %d" contatore

Ma questa pratica è scoraggiata in stile funzionale!

Step 7 — Definire la tua prima funzione

Definiamo una semplice funzione. Usiamo la keyword let, il nome della funzione, i nomi dei parametri, il simbolo = per l’assegnazione del risultato, e infine l’espressione vera e propria.

let quadrato x = x * x

printfn "Il quadrato di 5 è: %d" (quadrato 5)

Nota come non abbiamo dichiarato il tipo di x né il tipo di ritorno. In realtà F# è un linguaggio statico, ed il tipo viene dedotto implicitamente dal contesto. Il compilatore capisce che x è un int perché viene usato con l’operatore *.

Esegui il programma e vedrai:

Il quadrato di 5 è: 25

Step 8 — Type Inference: lascia lavorare il compilatore

F# è un linguaggio statico, ed il tipo viene dedotto implicitamente dal contesto. Questo si chiama type inference. Prova a hovering col mouse sulla funzione quadrato nel tuo editor: vedrai la signature int -> int, che significa “funzione che prende un int e restituisce un int”.

Se vuoi una funzione che accetti float:

let quadratoFloat (x: float) = x * x
printfn "Quadrato di 3.5: %f" (quadratoFloat 3.5)

Oppure puoi forzare il tipo usando .0:

let quadratoFloat2 x = x * x
let risultato = quadratoFloat2 3.5

Il compilatore deduce automaticamente che x è float perché viene chiamato con 3.5.

Step 9 — Liste e il pipe operator

Le liste sono fondamentali in F#. Ecco come crearle:

let numeri = [1; 2; 3; 4; 5]
let nomi = ["Alice"; "Bob"; "Charlie"]

Il simbolo ; separa gli elementi. Puoi anche creare range:

let da1a10 = [1..10]

Ora vediamo il pipe operator |>, una delle feature più amate di F#:

let sommaQuadrati n =
    [1..n]
    |> List.map quadrato
    |> List.sum

printfn "Somma dei quadrati da 1 a 5: %d" (sommaQuadrati 5)

Il pipe operator passa l’output di un’espressione come input della successiva. Leggi il codice così: “Crea una lista da 1 a n, poi mappala applicando la funzione quadrato, poi somma tutti gli elementi”.

Attenzione: In F#, lo spazio è il separatore standard per i parametri di funzione. Raramente servono parentesi e, in particolare, non usare parentesi quando chiami una funzione.

Step 10 — Pattern Matching: la killer feature

Il pattern matching è una delle caratteristiche più potenti di F#. Ecco un esempio:

let descriviNumero x =
    match x with
    | 0 -> "Zero"
    | 1 -> "Uno"
    | 2 -> "Due"
    | _ -> "Altro numero"

printfn "%s" (descriviNumero 0)
printfn "%s" (descriviNumero 5)

match è simile a uno switch, ma molto più potente. L’underscore _ è il pattern “catch-all” che matcha qualsiasi valore.

Pattern matching con tuple:

let descriviCoppia (x, y) =
    match (x, y) with
    | (0, 0) -> "Origine"
    | (0, _) -> "Asse Y"
    | (_, 0) -> "Asse X"
    | _ -> "Punto generico"

Step 11 — Tuple e Record

Tuple:

Se ha una virgola, è una tupla. E una tupla è un oggetto, non due.

let coppia = (42, "risposta")
let (numero, testo) = coppia
printfn "Numero: %d, Testo: %s" numero testo

Record:

I record sono tipi strutturati immutabili:

type Persona = {
    Nome: string
    Eta: int
}

let alice = { Nome = "Alice"; Eta = 30 }
printfn "Nome: %s, Età: %d" alice.Nome alice.Eta

Step 12 — F# Interactive (FSI): la REPL

Visual Studio fornisce un secondo metodo più comodo per eseguire al volo il codice: un prompt interattivo attivabile dal menu. In VS Code con Ionide, puoi selezionare del codice e premere Alt+Enter per inviarlo a FSI.

Oppure, dal terminale:

dotnet fsi

Ora puoi scrivere codice F# interattivamente:

> let saluta nome = printfn "Ciao, %s!" nome;;
val saluta : nome:string -> unit

> saluta "Mario";;
Ciao, Mario!

Le righe in FSI vengono terminate con ;;. Questo perché FSI consente di immettere più righe. Il ;; alla fine comunica a FSI quando il codice è terminato.

Step 13 — Ricorsione: il cuore della programmazione funzionale

In F#, la ricorsione è preferita ai loop tradizionali. Ecco il classico fattoriale:

let rec fattoriale n =
    if n <= 1 then
        1
    else
        n * fattoriale (n - 1)

printfn "Fattoriale di 5: %d" (fattoriale 5)

La keyword rec indica che la funzione è ricorsiva. Assicurati che le funzioni ricorsive siano tail-recursive per prevenire stack overflow.

Versione tail-recursive:

let fattorialeTailRec n =
    let rec loop acc n =
        if n <= 1 then acc
        else loop (acc * n) (n - 1)
    loop 1 n

Step 14 — Confronto rapido con C#

C# si basa su principi orientati agli oggetti e imperativi, mentre F# si basa su principi funzionali.

Confronto per somma dei quadrati:

F#:

let sommaQuadrati n = [1..n] |> List.map (fun x -> x*x) |> List.sum

C# (tradizionale):

public static int SommaQuadrati(int n) {
    int sum = 0;
    for (int i = 1; i <= n; i++) {
        sum += i * i;
    }
    return sum;
}

C# (LINQ, stile funzionale):

public static int SommaQuadrati(int n) {
    return Enumerable.Range(1, n)
        .Select(i => i * i)
        .Sum();
}

F# è più espressivo e ha una sintassi più compatta rispetto alla maggior parte dei linguaggi di programmazione, quindi puoi fare di più con meno codice.

Step 15 — Creare un programma più complesso

Mettiamo insieme tutto. Creiamo un convertitore Pig Latin:

let isVowel (c: char) =
    match c with
    | 'a' | 'e' | 'i' | 'o' | 'u'
    | 'A' | 'E' | 'I' | 'O' | 'U' -> true
    | _ -> false

let toPigLatin (word: string) =
    if word.Length = 0 then
        word
    elif isVowel word.[0] then
        word + "yay"
    else
        word.[1..] + string(word.[0]) + "ay"

let frase = "hello world from fsharp"
let parolePigLatin =
    frase.Split(' ')
    |> Array.map toPigLatin
    |> String.concat " "

printfn "Originale: %s" frase
printfn "Pig Latin: %s" parolePigLatin

Questo programma:

  1. Definisce una funzione isVowel con pattern matching
  2. Implementa toPigLatin che trasforma una parola
  3. Usa il pipe operator per processare un’intera frase

Verifica del risultato

Esegui dotnet run nella directory del tuo progetto. Dovresti vedere output simili a quelli mostrati negli esempi.

Per verificare che il tuo ambiente funzioni correttamente:

dotnet --version        # Verifica SDK installato
dotnet fsi             # Avvia F# Interactive

In FSI, prova:

> let test = 42;;
> printfn "Test: %d" test;;

Se vedi l’output Test: 42, tutto funziona!

Troubleshooting comuni

In F# probabilmente non arriverai lontano, perché il compilatore è molto più rigoroso. Il miglior strumento per debuggare gli errori del compilatore è il tuo cervello, e F# ti costringe a usarlo!

Errore: “This value is not a function”

Otterrai errori sul passaggio del tipo sbagliato di parametro, o troppo pochi parametri. Esempio:

// Sbagliato:
let somma x y = x + y
let risultato = somma (1, 2)  // Errore! Stai passando una tupla

// Corretto:
let risultato = somma 1 2     // Passa due argomenti separati

Errore di tipo mismatch

F# è fortemente tipizzato. Se provi a mixare int e float:

let x = 5
let y = 3.0
let z = x + y  // Errore! int + float non è permesso

// Corretto:
let z = float x + y  // Converti x a float

Problemi con l’indentazione

I blocchi di codice sono identificati dai rientri di uno o più spazi (indentazione). Se il compilatore si lamenta in modo criptico, controlla l’indentazione:

// Sbagliato:
let funzione x =
let y = x + 1
y * 2

// Corretto:
let funzione x =
    let y = x + 1
    y * 2

Ionide non funziona in VS Code

Se hai fatto modifiche al sistema o installato prerequisiti Ionide con Visual Studio Code aperto, riavvia Visual Studio Code. Assicurati anche che il .NET SDK sia nel PATH.

Best practice e next step

Best practice:

  1. Preferisci l’immutabilità: evita mutable a meno che non sia strettamente necessario
  2. Sfrutta il type inference: dichiara i tipi solo quando serve disambiguare
  3. Usa il pipe operator: rende il codice più leggibile e “narrativo”
  4. Pattern matching over if-else: è più espressivo e type-safe
  5. Metti le cose con “tipi noti” prima delle cose con “tipi sconosciuti”. In particolare, potresti riordinare le pipe e funzioni concatenate in modo che gli oggetti tipizzati vengano prima.

Prossimi passi:

  • Studia i Discriminated Unions, una feature killer di F# per modellare domini complessi
  • Esplora i Computation Expressions (simili alle monadi)
  • Impara i Type Providers per accedere a dati esterni (JSON, database, web) con tipi generati automaticamente
  • Leggi il classico “Domain Modeling Made Functional” di Scott Wlaschin
  • Sperimenta con Fable per compilare F# in JavaScript

F# gira su .NET — il runtime enterprise più diffuso al mondo. Questo significa accesso a tutte le librerie .NET, compatibilità con C#, e la possibilità di usare F# in produzione con infrastruttura già esistente.

Conclusione

Hai appena completato il tuo primo viaggio in F#! Hai imparato a installare e configurare l’ambiente, scrivere funzioni pure, sfruttare l’immutabilità e il type inference, usare il pattern matching e il pipe operator, e hai capito le differenze fondamentali tra programmazione funzionale e imperativa.

F# ti dà semplicità come Python con correttezza, robustezza e performance oltre C# o Java. Il linguaggio ti guiderà verso codice più robusto e manutenibile, sfruttando la potenza del compilatore per catturare errori prima che diventino bug.

Ora hai le basi per esplorare feature più avanzate. Continua a esercitarti, sperimenta con F# Interactive, e non aver paura di commettere errori: il compilatore F# è il tuo migliore alleato!

Buon coding funzionale! 🚀

Domande frequenti

F# è difficile da imparare se conosco già C#?
No, anzi! Conoscere C# è un vantaggio perché condividono la piattaforma .NET. La sfida principale è il cambio di paradigma: da orientato agli oggetti a funzionale-first. Ci vogliono circa 2-3 settimane per un developer C# per sentirsi comodo con F#, soprattutto se si è aperti a imparare. Il vantaggio è che F# ti insegna concetti che miglioreranno anche il tuo codice C#.
Posso usare le librerie .NET standard in F#?
Assolutamente sì! F# ha pieno accesso a tutto l'ecosistema .NET. Puoi usare qualsiasi libreria NuGet, chiamare codice C#, e viceversa. F# compila in IL (Intermediate Language) esattamente come C#, quindi l'interoperabilità è eccellente. Alcuni design pattern OOP potrebbero sembrare meno naturali in F#, ma tecnicamente tutto funziona.
Quando dovrei scegliere F# invece di C#?
F# eccelle in: data processing e analisi, domain modeling complesso, applicazioni concorrenti/parallele, scripting e prototipazione rapida, e quando vuoi minimizzare i bug attraverso l'immutabilità. C# è ancora migliore per: applicazioni enterprise con team molto grandi, progetti con forte legacy OOP, e quando il pool di sviluppatori disponibili è una priorità. Molti team usano entrambi: F# per la business logic critica, C# per l'infrastruttura.
Perché gli errori del compilatore F# sono difficili all'inizio?
Il compilatore F# è estremamente rigoroso e spesso gli errori si propagano: un problema in una riga può causare errori in cascata altrove. Il trucco è leggere l'errore dalla prima occorrenza e lavorare top-down nel file. Con l'esperienza, impari a "pensare come il compilatore". Usa F# Interactive per testare piccoli pezzi di codice isolatamente: questo ti aiuta a capire dove sta il problema senza essere sopraffatto.
F# ha futuro nel 2026 e oltre?
Sì. F# 10 è uscito con .NET 10 nel 2025, dimostrando che Microsoft continua a investire attivamente. La community è piccola ma estremamente attiva, con progetti come Fable (F# to JavaScript), Ionide, e framework web come Giraffe. Aziende come Jet.com (acquisita da Walmart per $3.3 miliardi) hanno costruito architetture intere in F#. Il linguaggio è stabile, maturo, e perfetto per team che vogliono qualità del codice superiore.

Redazione

Appassionato di tecnologia e innovazione. Testo e recensisco prodotti per aiutarti a fare la scelta migliore.

Scopri di più

Nota di trasparenza

Questo articolo contiene link affiliati Amazon. Se acquisti tramite questi link, potremmo ricevere una piccola commissione senza costi aggiuntivi per te. I prezzi possono variare: verifica sempre il prezzo aggiornato su Amazon. Le nostre opinioni restano indipendenti e non influenzate. Maggiori informazioni.

Condividi questo articolo