Based on the polynomial functors described in Niu and Spivak
- libraries for Scala 3.4+ (JS, JVM, and Native platforms)
- mermaid integration (optional)
"com.julianpeeters" %% "polynomial" % "0.6.0" // required
"com.julianpeeters" %% "polynomial-mermaid" % "0.6.0" // optionalThe polynomial library provides the following implementation of poly:
- objects: built-in ADTs for monomial, binomial, and trinomial
StoreandInterfacefunctors - morphisms:
PolyMap, or~>, a natural transformation between polynomial functors - products:
Cartesian, or×, a categorical product implemented as match typesComposition, or◁, a substitution product implemented as match typesTensor, or⊗, a parallel product implemented as match types
import polynomial.`object`.*
import polynomial.morphism.~>
// Examples
type `2y⁵¹²` = Monomial.Interface[(Byte, Boolean), Boolean, _]
type `y² + 2y` = Binomial.BiInterface[Boolean, Unit, Unit, Boolean, _]
type `2y²` = Monomial.Store[Boolean, _]
type `0` = Monomial.Interface[Nothing, Nothing, _]
type `1` = Monomial.Interface[Unit, Nothing, _]
type `y² + 2y → 2y⁵¹²` = (`y² + 2y` ~> `2y⁵¹²`)[_]Q: What are we losing by using simple types rather than dependent types?
A: Simple types can easily model monomial lenses, but they are not flexible enough to model fully dependent lenses.
However, a rich subset of dependent lenses can be implemented, under the following constraints:
- the positions and directions of the polynomial are related by an ADT
- the number of terms in the polynomial is equal to the number of members of the ADT
For example,
Bilens can be pameterized byOptionsuch that its terms are exponentiated bySome[A]andNone.type, and behaves as a dual-channeled monomial lens.
Certain lenses can be interpreted graphically. Given a Mermaid instance for a
PolyMap, a mermaid flowchart definition can
be printed, with titles and labels in the following formats:
Cardinal: render exponents and coefficients as integer valuesCustom: render custom labels for variables, exponents and coefficientsGeneric: render exponents and coefficients as, e.g.,Ainstead of aByteSpecific: render exponents and coefficients as, e.g.,Byteinstead of aA
import polynomial.`object`.Monomial.{Interface}
import polynomial.mermaid.{Format, Mermaid, given}
import polynomial.morphism.~>
type F[Y] = (Interface[Byte, Char, _] ~> Interface[Byte, Char, _])[Y]
val M: Mermaid[F] = summon[Mermaid[F]]
// M: Mermaid[F] = polynomial.mermaid.Mermaid$$anon$3@49cbc7e8
println(M.showGraph(graphFmt = Format.Generic))
// ```mermaid
// graph LR;
// A1:::hidden---|<span style="font-family:Courier">A<sub>2</sub></span>|A_B1[ ]:::point
// subgraph s[ ]
// A_B1:::point---QB1
// QB1[<span style="font-family:Courier">B<sub>1</sub></span>𝑦<sup><span style="font-family:Courier">A<sub>1</sub></span></sup>]:::empty
// QB1---B_B1
// end
// B_B1[ ]:::point---|<span style="font-family:Courier">B<sub>2</sub></span>|B1:::hidden;
//
// classDef empty fill:background;
// classDef point width:0px, height:0px;
// classDef title stroke-width:0px, fill:background;
// ```graph LR;
A:::hidden---|Byte|S[Boolean]---|Char|B:::hidden;
classDef empty fill:background;
classDef point width:0px, height:0px;
classDef title stroke-width:0px, fill:background;
(Note: GitHub currently ignores formatting, please use mermaid.live)