FPropose 1.2.0
dotnet add package FPropose --version 1.2.0
NuGet\Install-Package FPropose -Version 1.2.0
<PackageReference Include="FPropose" Version="1.2.0" />
<PackageVersion Include="FPropose" Version="1.2.0" />
<PackageReference Include="FPropose" />
paket add FPropose --version 1.2.0
#r "nuget: FPropose, 1.2.0"
#:package FPropose@1.2.0
#addin nuget:?package=FPropose&version=1.2.0
#tool nuget:?package=FPropose&version=1.2.0
FPropose
Composable predicates for F# that return a boolean and explain why that result holds for a specific value. Explanations can follow normal short-circuiting (Lazy) or evaluate every sub-predicate for auditing (Eager).
Install
dotnet add package FPropose
Quick example
open FPropose
open FPropose.Operators
let canVote =
Pred.leafMsg "age" (fun p -> p.Age >= 18)
(fun _ -> "Meets minimum age.")
(fun p -> $"Age {p.Age} is below 18.")
let registered =
Pred.leafMsg "registered" (fun p -> p.Registered)
(fun _ -> "Account is registered.")
(fun _ -> "Account is not registered.")
let p = canVote .&&. registered
let person = {| Name = "Ada"; Age = 17; Registered = false |}
if Pred.eval p person then
printfn "OK"
else
printfn "%s" (Pred.explainText ExplainMode.Lazy p person)
ExplainTree captures structure; call .Format() or ExplainTree.format for plain text.
API overview
| Construct | Use |
|---|---|
Pred.leaf name test explain |
Atomic test; explain receives the value and the pass/fail flag. |
Pred.leaf' test explain |
Same as leaf, without a separate display name (detail only in formatted output). |
Pred.leafMsg name test onTrue onFalse |
Convenience when messages differ only by outcome. |
Pred.leafMsg' test onTrue onFalse |
Same as leafMsg, without a separate display name. |
Pred.conj / Pred.disj / Pred.neg |
AND, OR, NOT. |
Pred.all / Pred.any |
Fold over lists (all [] is always true; any [] always false). |
Pred.forAll name getItems inner |
Every element from getItems must satisfy inner; nested explanations per item (empty sequence is vacuously true). |
Pred.forAll' getItems inner |
Same as forAll, without a separate quantifier label in formatted output. |
Pred.exists name getItems inner |
At least one element from getItems must satisfy inner; nested explanations per item (empty sequence is vacuously false). |
Pred.exists' getItems inner |
Same as exists, without a separate quantifier label in formatted output. |
Pred.contramap |
Focus a predicate on part of a larger value. |
Pred.eval |
Boolean result with standard short-circuiting for AND and OR. |
Pred.explain |
PropositionResult using lazy explanation. |
Pred.explainWith ExplainMode.Eager |
Full sub-tree regardless of short-circuit. |
Pred.explainText |
Same as explain, rendered as a string. |
FPropose.Operators |
.&&., .\|\|., ~~~ |
Developing locally
Prerequisites: .NET 8 SDK.
git clone https://github.com/icalvo/FPropose.git
cd FPropose
dotnet restore
dotnet build
dotnet test
Open as a workspace
In Cursor or VS Code, use File → Open Folder and select the FPropose directory (the folder that contains FPropose.sln).
Repository
Source lives at github.com/icalvo/FPropose. If you cloned without a remote:
git remote add origin https://github.com/icalvo/FPropose.git
git push -u origin master
Project layout
CHANGELOG.md— release history (Keep a Changelog)src/FPropose— library (Explain.fs,Pred.fs)tests/FPropose.Tests— xUnit tests
Agent releases: load the deploy-release skill (.cursor/skills/deploy-release/SKILL.md) for changelog → tag → GitHub Release → NuGet publish.
Packaging locally
dotnet pack src/FPropose/FPropose.fsproj -c Release -o ./artifacts -p:PackageVersion=0.1.0-local
Outputs .nupkg (and symbols) under ./artifacts.
Publishing to NuGet.org (CI)
One-time setup
- Use this repository (
icalvo/FPropose);Directory.Build.propsand this README already point at it. - Create an API key on NuGet.org with Push scope for package id
FPropose. - In the GitHub repo, add a secret named
NUGET_API_KEYcontaining that key (Settings → Secrets and variables → Actions).
Publish when you cut a GitHub Release
- Update
Version/ release notes as needed. - Create a Release in GitHub and publish it. Use a tag like
v0.2.0(the workflow strips a leadingvfor the package version). - The Publish to NuGet workflow packs
FProposeand runsdotnet nuget pushtohttps://api.nuget.org/v3/index.json.
Publish manually from Actions
- Go to Actions → Publish to NuGet → Run workflow.
- Enter a SemVer version (e.g.
0.2.0).
After the first publish
Confirm the package appears on NuGet Gallery. If the id is taken, change <PackageId> in src/FPropose/FPropose.fsproj and the secret scope to match.
License
MIT — see LICENSE.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net8.0
- FSharp.Core (>= 10.1.300)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.