Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Write, review, or modernize F# code in .NET repositories with functional-first design, algebraic data types, pattern matching, pipelines, async workflows, project ordering, and C# interop. USE FOR: F# .fs/.fsproj code; discriminated unions, records, options, results, pattern matching, computation expressions, or functional domain modeling; strongly typed AI-generated .NET code. DO NOT USE FOR: C# language modernization; FSI-only exploratory scripts with no project changes. INVOKES: inspect .fspr
.claude/skills/managedcode-fsharp/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-02 | ✗→✓ | ▲ Improved | 11% | 0% |
| case-08 | ✗→✓ | ▲ Improved | 34% | 0% |
| case-04 | ✓→✓ | = Same ✓ | 23% | 0% |
| case-14 | ✓→✓ | = Same ✓ | 48% | 0% |
| case-01 | ✓→✓ | = Same ✓ | 396% | 0% |
.fs, .fsx, .fsi, or .fsproj filesmodern-csharpfsiUse the .NET SDK templates when adding F# projects.
bashdotnet new classlib -lang "F#" -o src/Domain dotnet new console -lang "F#" -o src/App dotnet new xunit -lang "F#" -o tests/Domain.Tests dotnet sln add src/Domain/Domain.fsproj tests/Domain.Tests/Domain.Tests.fsproj dotnet add tests/Domain.Tests/Domain.Tests.fsproj reference src/Domain/Domain.fsproj dotnet build
FSharp.Core is normally supplied by the F# SDK project. Add or pin it explicitly only when the repo has a package policy that requires deterministic package versions.
bashdotnet add src/Domain/Domain.fsproj package FSharp.Core
F# compiles files in the order listed in the project file. Define types and modules before files that consume them.
xml<ItemGroup> <Compile Include="Domain.fs" /> <Compile Include="Validation.fs" /> <Compile Include="Program.fs" /> </ItemGroup>
When adding a file, update the .fsproj intentionally. Do not assume wildcard ordering.
.fsproj, .fs, .fsi, and .fsx files to determine compile order, public boundaries, and whether the code is F#-first or C#-facing.option for absence, and Result for expected failures..fsproj compile list before consumers reference the new code.Try* patterns when C# callers need a stable surface.dotnet build, targeted tests, and any relevant dotnet fsi probes before returning the final result.fsi for exploratory scripts, but move durable code into ordered .fsproj files before it becomes production behavior.Prefer a type that names every valid state over loose strings, nullable values, or parallel booleans.
fsharpmodule Orders type OrderId = private OrderId of string module OrderId = let tryCreate value = if System.String.IsNullOrWhiteSpace value then Error "Order id is required." else Ok (OrderId value) type Payment = | Card of last4: string | Wire of iban: string | PurchaseOrder of number: string type Order = { Id: OrderId Customer: string Payment: Payment } let describePayment payment = match payment with | Card last4 -> $"card ending {last4}" | Wire iban -> $"wire transfer {iban}" | PurchaseOrder number -> $"purchase order {number}"
Return Result<'T,'Error> when callers must handle failure and when failures are part of the domain.
fsharpmodule Pricing type Price = private | Price of decimal module Price = let tryCreate amount = if amount < 0m then Error "Price cannot be negative." else Ok (Price amount) let value (Price amount) = amount type Line = { Sku: string Quantity: int UnitPrice: Price } let tryCreateLine sku quantity amount = match Price.tryCreate amount with | Ok price when quantity > 0 -> Ok { Sku = sku; Quantity = quantity; UnitPrice = price } | Ok _ -> Error "Quantity must be positive." | Error message -> Error message
Use pipelines for readable transformations, but stop before the pipeline hides error handling or allocation cost.
fsharpopen System.IO let readActiveUsers path = File.ReadLines path |> Seq.skip 1 |> Seq.choose (fun line -> match line.Split(',') with | [| id; name; "active" |] -> Some {| Id = id; Name = name |} | _ -> None) |> Seq.toList
Make public interop APIs easy for C# callers. Hide F#-specific details behind functions, methods, or DTO records when needed.
fsharpnamespace Company.Domain type InvoiceDto = { Id: string Total: decimal IsPaid: bool } module Invoice = let markPaid invoice = { invoice with IsPaid = true }
option internally; translate to nullable annotations, Try* methods, or Result at C#-first public boundaries.task { } or Task-returning APIs at .NET interop boundaries; use Async<'T> when the code is F#-first..fsproj compile order matches dependency order.option or Result, not undocumented null.Run the narrowest relevant checks after changes:
bashdotnet build dotnet test dotnet fsi scripts/check.fsx
If adding a new F# file, also inspect the project file diff to confirm the compile order is deliberate.
Other measured skills in the registry, with their headline benchmark lift.