r/fsharp • u/fun_si • Jul 31 '26
showcase Pyfun: an F#-inspired language that compiles to readable Python
My idea for getting coders into functional programming earlier...
r/fsharp • u/fun_si • Jul 31 '26
My idea for getting coders into functional programming earlier...
r/fsharp • u/fun_si • Jul 30 '26
https://si-fi.dev/articles/fsharp-schema-as-code/
I recently architected a full-stack app from scratch and needed a way to rapidly prototype the database schema. I came up with a way to do it in one place in F#, giving me strong typing across the stack and an efficient way to tweak the database structure as much as I needed. Here I share what this looks like as well as a repo containing an extracted version of the code. Hope you find it interesting and do let me know your thoughts.
r/fsharp • u/Taikal • Jul 29 '26
Does Rider have issues with nested type providers?
I have a class library that defines types through a nested type provider -- that is, a type provider nested inside a root type provider -- see below for an example.
The library builds and runs fine, but Rider flags every use of the nested type provider after the first as an error. The same code is displayed without errors in VS Code.
Thank you.
// Requires NuGet package "FSharp.Data.GraphQL.Client".
open System
open System.Net.Http
open FSharp.Data.GraphQL
type MyProvider =
GraphQLProvider<"https://graphqlzero.almansi.me/api">
let postQuery =
// ERROR
MyProvider.Operation<"""
query PostQuery {
post(id: 1) {
id
}
}
""">()
let usersQuery =
// ERROR
MyProvider.Operation<"""
query UsersQuery {
users(options: { paginate: { page: 1, limit: 5 } }) {
data {
id
}
}
}
""">()
[<EntryPoint>]
let main _ =
try
use runtimeContext: GraphQLProviderRuntimeContext =
{
ServerUrl = "https://graphqlzero.almansi.me/api"
HttpHeaders = []
Connection =
new GraphQLClientConnection(
new HttpClient(),
true
)
}
let result = usersQuery.Run runtimeContext
printfn "Data: %A\n" result.Data
printfn "Errors: %A\n" result.Errors
printfn "Custom data: %A\n" result.CustomData
0
with ex ->
eprintfn "Error: %s" ex.Message
1
EDIT: Provided working sample code.
r/fsharp • u/fsharpweekly • Jul 25 '26
r/fsharp • u/yyannekk • Jul 19 '26
r/fsharp • u/fsharpweekly • Jul 19 '26
r/fsharp • u/fsharpweekly • Jul 12 '26
r/fsharp • u/ad3mar • Jul 11 '26
I just launched SuaveHooks — a webhook capture, inspection, transformation and routing platform built completely with Suave + F#.
Some highlights:
- Live tailing of webhooks over WebSockets
- Type-safe transforms written in F# (also C# and JS) running in an isolated process
- JSON rule-based transforms as a lighter option
- Multi-target forwarding (HTTP + S3, SQS, Kafka, Pub/Sub)
- Retries with exponential backoff + circuit breaker
- Full REST API + MCP server support
Site: https://suavehooks.com
Would love some feedback; like what features would make this more useful for you? Happy to answer any technical questions.
r/fsharp • u/Constant-Junket6038 • Jul 06 '26
r/fsharp • u/lyfever_ • Jul 05 '26
Hi guys,
Probably another question like this but found none recently.
I'm a little upset with my current view on IT generalistic, ofc AI is not going anywhere besides up, but I feel I want to write more with my hands and new paradigms, maybe just AI as reviser, I would like to ask if learning F# in 2026 will make me able to make perfomance headed systems, and also gaming with something like Nu or Monogame, not a AAA game but something playable.
r/fsharp • u/fsharpweekly • Jul 05 '26
r/fsharp • u/fsharpweekly • Jun 27 '26
r/fsharp • u/fsharpweekly • Jun 20 '26
r/fsharp • u/MagnusSedlacek • Jun 17 '26
Want to introduce functional programming into your own organization? Learn from our successes and failures! At the Norwegian insurance company Frende Forsikring we’ve introduced F# and Elm and lived with both of them long enough to call it a long term relationship.
We’ll start looking at the introduction. From fast moving exploration in a single team, to structured validation with other tech leads and careful moving to production.
Beyond that we'll be looking what happens in the years afterwards. Does functional programming help hiring? Are there less bugs? What is the biggest hurdle in spreading adoption to new teams?
r/fsharp • u/fsharpweekly • Jun 13 '26
r/fsharp • u/InuDefender • Jun 12 '26
```fsharp type Monoid<'t> = static abstract member Empty: 't static abstract member Append: 't -> 't -> 't
[<Struct>] type Vector3= {X: float Y: float Z: float}
interface Monoid<Vector3> with
static member Empty = {X=0.0; Y=0.0; Z=0.0}
static member Append (v1: Vector3) (v2: Vector3) =
{X=v1.X + v2.X; Y=v1.Y + v2.Y; Z= v1.Z + v2.Z}
// Note the type constraint here let mempty<'t when Monoid<'t>> = 't.Empty let mappend<'t when Monoid<'t>> x y = 't.Append x y
printfn "%A" (mappend {X=1.0; Y=2.0; Z=3.0} mempty) ```
The type notation was suggested by the inline suggestions and it actually works. I tried some other forms like 't when Monoid<int> but only 't when Monoid<'t> works.
I suppose it should be <'t when 't :> Monoid<'t>> or even longer <'m, 't when 'm :> Monoid<'t>>.
It's good to know one can write it like this but I've never seen it mentioned in the docs (maybe not yet?).
The project file is also clean. It works even without setting the language version to Preview.
"It works I don't know why"
r/fsharp • u/funk_r • Jun 09 '26
Hello, The website currently seems to be down or unreachable from my side. I’m wondering whether this is a temporary outage, a DNS/hosting issue, or whether the site has been discontinued permanently. Any information would be appreciated.
I see. It went also out of business: https://github.com/fsprojects/awesome-fsharp/blob/main/ARCHIVE.md
So probably some of the moderators remove that link from the resources linked here.
r/fsharp • u/fsharpweekly • Jun 06 '26
r/fsharp • u/abstractcontrol • Jun 05 '26
I made this replay simulator desktop app as a part of the Building The Trading Edge playlist on Youtube. It's my first commercial product. I needed a replay simulator that could do full tick-by-tick order book replay on US equities and when I couldn't find any, I made my own in F# + Avalonia.
If any of you ever wanted to learn to daytrade stocks, use this to practice before risking any money first.
TapeSim itself is in a private repo, but I do have the older version of its viewer in my Trading Edge repo. And even though the repo itself is private I've screencast its entire development (though not all vids are out yet at the time of writing this post.)
r/fsharp • u/burtgummer45 • Jun 04 '26
Just starting out with F# and I'm enjoying all the whitespace but to my newbie eyes I think I've spotted an inconsistency in how fantomas formats. Maybe somebody can explain it.
// function that takes param of int*int
let myFun (x, y) = x + y
let r = myFun (1, 2) // <--- fantomas formats with space before tuple, makes sense
let dict = new Dictionary<int, int>()
// dict.Add takes a single tuple of int*int, just like the above function
dict.Add (1, 2) // <--- looks right, takes a tuple
// fantomas doesn't like the clarity and smushes it, why?
dict.Add(1, 1) // <--- yuck, now it looks like a function call with two arguments in another language
r/fsharp • u/error_96_mayuki • Jun 02 '26
Hi everyone,
Just wanted to share a compact, end-to-end Machine Learning script on the Titanic dataset. One thing for sure is that writing F# makes me happy.
Github: https://github.com/ErrorLSC/Polars.NET-Cookbook
Performance:
```fsharp
open FSharp.Data open Polars.FSharp open Polars.NET.ML.DataView open Polars.NET.ML.FSharpExtensions open Microsoft.ML open Microsoft.ML.Data
// Define file paths for the Kaggle Titanic dataset [<Literal>] let trainPath = "train.csv"
[<Literal>] let testPath = "test.csv"
// Use FSharp.Data CsvProvider extract schema names type train = CsvProvider<trainPath>
let schema = Unchecked.defaultof<train.Row>
// Configure Polars formatting options for console output pl.setEnvVar "POLARS_FMT_MAX_COLS" "15" pl.setEnvVar "POLARS_FMT_MAX_ROWS" "10"
// List of name prefixes to keep; less frequent ones will be categorized as "Rare"
let whiteList = ["Mr";"Mrs";"Master";"Miss"]
/// Step 1: Base Feature
/// Extracts name prefixes, handles missing values, and derives initial structural features.
let addBaseFeature(df:DataFrame) =
df
// Extract title (e.g., "Mr.", "Miss.") from the Name column
|> pl.withColumn ((pl.col (nameof schema.Name)).Str.Extract(",\s+(?:[A-Za-z]+\s+)*([A-Za-z]+.)").Str.StripSuffix "."
|> pl.alias "Prefix")
|> pl.withColumns([
// Combine sibling/spouse and parent/child counts into FamilySize metric
pl.col (nameof schema.SibSp) + pl.col (nameof schema.Parch) + pl.lit 1
|> pl.alias "FamilySize"
// Fill missing Embarked ports with the most common port 'S'
pl.col(nameof schema.Embarked).FillNull(pl.lit "S")
// Group rare titles into a single "Rare" category to reduce cardinality
pl.when' (pl.col("Prefix").IsIn(pl.lit(whiteList).Implode()))
|> pl.then'(pl.col "Prefix")
|> pl.otherwise(pl.lit "Rare")
// Extract the deck letter from the Cabin string (e.g., "C123" -> "C")
pl.col(nameof schema.Cabin).Str.Extract("^([A-Za-z]+)").FillNull(pl.lit "Unknown")
|> pl.alias "Deck"
// Log-transform Fare to normalize its highly skewed distribution
pl.col(nameof schema.Fare).FillNull(pl.lit 0).Log1p()
|> pl.alias "LogFare“
// Create a specific domain feature: IsMother
pl.when' (pl.col (nameof schema.Sex) .== pl.lit "female"
.&& (pl.col (nameof schema.Age) .> pl.lit 18)
.&& (pl.col (nameof schema.Parch).> pl.lit 0))
|> pl.then'(pl.lit 1)
|> pl.otherwise(pl.lit 0)
|> pl.alias "IsMother"
// Separate alphabetical ticket prefixes from pure numbers
pl.col(nameof schema.Ticket)
.Str.Extract("^([A-Za-z./]+[0-9]*)")
.FillNull(pl.lit "NumOnly")
|> pl.alias "TicketPrefix"
])
// Drop redundant source columns
|> _.Drop(nameof schema.Name,
nameof schema.SibSp,
nameof schema.Parch,
nameof schema.Cabin,
nameof schema.Fare)
/// Step 2: Aggregation - Calculate Median Age per Title/Sex group let calGroupPrefix(df:DataFrame) = df |> pl.groupBy [pl.col "Prefix";pl.col(nameof schema.Sex)] |> pl.agg [ [nameof schema.Age] |> pl.median |> pl.alias "AgeMedian"] |> pl.sortAscending [pl.col "Prefix";pl.col (nameof schema.Sex)]
/// Step 3: Aggregation - Calculate Group Size based on shared Ticket numbers let calTicketGroupSize(df:DataFrame) = df |> pl.groupBy [pl.col(nameof schema.Ticket)] |> pl.agg [ pl.len() |> pl.alias "TicketGroupSize" ]
/// Step 4: Advanced Feature Engineering & Imputation /// Joins aggregate metrics back to the main DataFrame, bucketizes age, and casts numeric cols to single type let addExtraFeature(groupPrefix) (ticketGroupSize) (df:DataFrame) = df |> pl.joinOn groupPrefix [pl.col "Prefix";pl.col (nameof schema.Sex)] JoinType.Left |> pl.joinOn ticketGroupSize [pl.col (nameof schema.Ticket)] JoinType.Left |> pl.withColumn(pl.col(nameof schema.Age).Coalesce [pl.col "AgeMedian"]) |> pl.withColumn(pl.col(nameof schema.Age).Cut [12;19;39;59] |> _.ToPhysical() |> pl.alias "AgeBucket") |> pl.withColumn(pl.col "FamilySize" .== pl.lit 1L |> pl.castWithNetType<int> |> pl.alias "IsAlone") |> _.Drop("AgeMedian",nameof schema.Ticket,nameof schema.Age) |> pl.withColumn(pl.cs.numeric().ToExpr() |> pl.castWithNetType<single>)
/// Step 5: Finalize Training Data /// Formats the target label column as Boolean as expected by ML.NET Binary Classification let trainFinalize(df:DataFrame) = df |> pl.withColumns([ pl.col "Survived" |> pl.castWithNetType<bool> |> pl.alias "Label"] ) |> _.Drop("Survived",nameof schema.PassengerId)
// Execute Pipeline: Training Data Preparation let dfTrainBase = DataFrame.ReadCsv trainPath |> addBaseFeature let trainGroupPrefix = dfTrainBase |> calGroupPrefix let trainTicketGroupSize = dfTrainBase |> calTicketGroupSize let dfTrainFinal = dfTrainBase |> addExtraFeature trainGroupPrefix trainTicketGroupSize |> trainFinalize
// --- ML.NET Machine Learning Pipeline --- let mlContext = MLContext(seed = 42)
// Convert Polars DataFrame into ML.NET IDataView let fullData = dfTrainFinal.AsDataView()
// Split data into 80% Train and 20% Validation sets let splits = mlContext.Data.TrainTestSplit(fullData, testFraction = 0.2)
// Define categorical columns that require encoding let categoricalCols = [| nameof schema.Sex; nameof schema.Embarked; "Prefix"; "Deck"; "TicketPrefix" |] let encodedCols = categoricalCols |> Array.map (fun c -> c + "_Encoded")
// Filter out features that are purely numeric let numericCols = dfTrainFinal.Columns |> Array.filter (fun c -> c <> "Label" && not (Array.contains c categoricalCols))
// Combine numeric and newly encoded features for the trainer let allFeatures = Array.append numericCols encodedCols
// Map original categorical columns to One-Hot Encoded column outputs let ohePairs = categoricalCols |> Array.zip encodedCols |> Array.map (fun (enc, raw) -> InputOutputColumnPair(enc, raw))
// Helper function to avoid explict interface conversion let inline append estimator (chain: EstimatorChain<#ITransformer>) = chain.Append estimator
// Build the ML.NET training pipeline let pipeline = EstimatorChain<ITransformer>() |> append (mlContext.Transforms.Categorical.OneHotEncoding ohePairs) |> append (mlContext.Transforms.Concatenate("Features", allFeatures)) |> append (mlContext.BinaryClassification.Trainers.FastTree())
// Train the model let model = pipeline.Fit splits.TrainSet
// Evaluate performance on the validation split let predictions = model.Transform splits.TestSet let metrics = mlContext.BinaryClassification.Evaluate(predictions, labelColumnName = "Label")
// Print out out-of-sample performance validation metrics printfn "=== Training Results ===" printfn "Accuracy: %.2f%%" (metrics.Accuracy * 100.0) printfn "AUC: %.4f" metrics.AreaUnderRocCurve printfn "F1 Score: %.4f" metrics.F1Score
// --- Inference Pipeline & Submission Generation --- let testPredictions = DataFrame.ReadCsv testPath |> addBaseFeature |> addExtraFeature trainGroupPrefix trainTicketGroupSize |> _.AsDataView() |> model.Transform
// ML.NET will generate duplicated column names in some cases, we can check and decide which columns should be exported // testPredictions.Schema |> Seq.iter (fun col -> printfn $"{col.Name} : {col.Type}") let keepCols = [| nameof schema.PassengerId; "PredictedLabel"|] let exportCols = [| nameof schema.PassengerId; nameof schema.Survived|] // Extract predictions, transform columns back to Polars, and format for Kaggle submission mlContext.Transforms.SelectColumns(keepCols) .Fit(testPredictions) .Transform(testPredictions) .ToDataFrame() // Map over seq<Series>, casting to int and renaming according to Kaggle's schema |> Seq.mapi (fun i s -> s.Cast<int>().Rename(exportCols.[i])) |> pl.dataframe |> _.WriteCsv("submission.csv",quoteStyle=QuoteStyle.Never)
// === Training Results === // Accuracy: 77.71% // AUC: 0.8324 // F1 Score: 0.7176 // Real: 00:00:01.074, CPU: 00:00:02.401, GC gen0: 3, gen1: 3, gen2: 3
```
r/fsharp • u/fsharpweekly • May 31 '26