diff --git a/Sources/Tests/FSharpWrapperUnitTests/FSharpWrapperUnitTests.fsproj b/Sources/Tests/FSharpWrapperUnitTests/FSharpWrapperUnitTests.fsproj
index f6a42a3e7..f987569cf 100644
--- a/Sources/Tests/FSharpWrapperUnitTests/FSharpWrapperUnitTests.fsproj
+++ b/Sources/Tests/FSharpWrapperUnitTests/FSharpWrapperUnitTests.fsproj
@@ -17,6 +17,7 @@
+
diff --git a/Sources/Tests/FSharpWrapperUnitTests/Functions.Systems.fs b/Sources/Tests/FSharpWrapperUnitTests/Functions.Systems.fs
new file mode 100644
index 000000000..a6a7fd4f3
--- /dev/null
+++ b/Sources/Tests/FSharpWrapperUnitTests/Functions.Systems.fs
@@ -0,0 +1,38 @@
+module AngouriMath.FSharp.Tests.Systems
+
+open AngouriMath.FSharp.Core
+open AngouriMath.FSharp.Functions
+open Xunit
+
+// https://github.com/asc-community/AngouriMath/issues/562. Version 2 of the two shapes proposed
+// there: the variables first and the equations second, which is how `solutions x expr` already
+// reads, rather than a separate EquationSystem type the caller has to know about. `equationSystem`
+// is still exposed for anyone who wants to build one and pass it around.
+
+[]
+let ``A linear system is solved over its variables`` () =
+ match solveSystem ["x"; "y"] ["x + y - 3"; "x - y - 1"] with
+ | Some solutions ->
+ Assert.Equal(1, solutions.RowCount)
+ Assert.Equal(parsed "2", solutions.[0, 0]) // columns follow the order of vars
+ Assert.Equal(parsed "1", solutions.[0, 1])
+ | None -> failwith "the system has a solution and should not have answered None"
+
+[]
+let ``An equality may be written out rather than moved to one side`` () =
+ let asEquality = solveSystem ["x"; "y"] ["x + y = 3"; "x - y = 1"]
+ let asExpression = solveSystem ["x"; "y"] ["x + y - 3"; "x - y - 1"]
+ Assert.Equal(asExpression.IsSome, asEquality.IsSome)
+ Assert.Equal(asExpression.Value.[0, 0], asEquality.Value.[0, 0])
+ Assert.Equal(asExpression.Value.[0, 1], asEquality.Value.[0, 1])
+
+/// An inconsistent system has no solution, and None is that rather than an empty matrix.
+[]
+let ``An inconsistent system answers None`` () =
+ Assert.True((solveSystem ["x"; "y"] ["x + y - 1"; "x + y - 2"]).IsNone)
+
+[]
+let ``A system can be built and passed around`` () =
+ let system = equationSystem ["x + y - 3"; "x - y - 1"]
+ Assert.NotNull(system)
+ Assert.True((system.Solve(symbol "x", symbol "y")) <> null)
diff --git a/Sources/Wrappers/AngouriMath.FSharp/Functions.fs b/Sources/Wrappers/AngouriMath.FSharp/Functions.fs
index b4ea3ab05..a8d294e00 100644
--- a/Sources/Wrappers/AngouriMath.FSharp/Functions.fs
+++ b/Sources/Wrappers/AngouriMath.FSharp/Functions.fs
@@ -250,3 +250,26 @@ let solutions x expr =
match parsed expr with
| :? Entity.Statement as statement -> statement.Solve(symbol x).InnerSimplified :?> Entity.Set
| func -> (equality func 0).Solve(symbol x).InnerSimplified :?> Entity.Set
+
+/// Returns a system of equations, built from a list of equalities or expressions.
+/// An expression that is not an equality is read as being equal to zero, exactly as
+/// `solutions` reads a single one.
+let equationSystem (equations : 'T list) =
+ MathS.Equations(equations |> List.map (fun eq ->
+ match parsed eq with
+ // EquationSystem reads each entry as being equal to zero, so an equality written out
+ // is moved to one side rather than handed over as a node -- passing the node makes the
+ // solver try to invert an equality, which it cannot do.
+ | :? Entity.Equalsf as equation -> equation.Left - equation.Right
+ | func -> func))
+
+/// Solves a system of equations over the given variables.
+///
+/// Each row of the resulting matrix is one solution and its columns follow the order of
+/// `vars`, so `solveSystem ["x"; "y"] ["x + y - 3"; "x - y - 1"]` answers `[[2, 1]]`:
+/// one solution, with x = 2 and y = 1. Returns None where none was found, rather than an
+/// empty matrix, since "no solution" and "the solver gave up" are the same answer here and
+/// neither is a matrix.
+let solveSystem (vars : 'T list) (equations : 'U list) =
+ (equationSystem equations).Solve(vars |> List.map symbol |> Array.ofList)
+ |> Option.ofObj