Styp (Sum TYPes) is written in Javascript, the library provides mechanisms for creating constructors and sum types or disjoint union types, the distribution size of the library is 611 bytes(Gzipped). This libary has been inspired by languages like Haskell
, F#
and OCaml
which provide sum types natively. Styp has also taken inspiration from daggy(a library for creating sum types in Javascript).
Example Code
const { tagged, sum } = require("styp");
const Polar = tagged("Polar", ["r", "theta"]);
let p1 = Polar(3, 0.88);
console.log(p1.toString()); // -> Polar(3,0.88)
const Maybe = sum("Maybe", {
Just: ["val"],
Nothing: []
});
let test1 = Maybe.Just(10);
console.log(test1.toString()); // -> Maybe.Just(10)
console.log(Maybe.is(test1)); // -> true
console.log(Maybe.Just.is(test1)); // -> true
console.log(Maybe.Nothing.is(test1)); // -> false
let times = Maybe.Nothing
.cata({
Just: x => x.val,
Nothing: () => 1
});
console.log(times * 5); // -> 5
Installation
Node
npm i styp
Browser
<script src="https://unpkg.com/styp"></script>
Documentation
Underconstruction!
tagged(typename: String, fields: Array[String]) -> Function | Object
This function takes typename and fields as params and returns a constructor function for the specified data type. In case of an empty fields array this function will return an object which you can use like a type with only one value.
const { tagged } = require("styp");
const Point = tagged("Point", ["x","y"]);
const nil = tagged("nil", []); // -> my custom null type
const p1 = Point(10,20);
const p2 = Point(5,5);
let temp = nil;
console.log(nil.is(temp));
console.log(temp.toString());
Every constructor functor has these methods: is
, from
,toString
. The instance created by constructor has toString
method and more methods can be added by the user more details are given below in the constructors section.
sum(typename: String, constructors: Object) -> Object
This function helps create a sum type (which is represented as an Object) it takes typename and an object which contains names of constructors and their fields(if any). The function returns an object which has all constructor functions (as specified in the passed constructors param).
const { sum } = require("styp");
const SafeDiv = sum("SafeDiv", [
Succ:["v"],
byZero: []
]);
const safelyDivide = (n,d) => d? SafeDiv.Succ(n/d): SafeDiv.byZero;
console.log(safelyDivide(10,2).toString());
console.log(safelyDivide(2,0).toString());
Constructors
Every constructor function/sum type object has the following methods defined -
and
{constructor}.toString() -> String
const { tagged } = require("styp");
const Point = sum("Point", {
Cartesian: ["x","y","z"],
Polar: ["r","theta"]
});
console.log(Point.toString()); // -> Point
console.log(Point.Cartesian.toString()); // -> Point.Cartesian
console.log(Point.Polar.toString()); // -> Point.Polar
{constructor}.is(obj: Object) -> Boolean
const { tagged } = require("styp");
const Point = tagged("Point", ["x","y"]);
let p1 = Point(2, 7);
console.log(Point.is(p1)); // -> true
console.log(Point.is({ random:true })); // -> false
{constructor}.from(obj: Object) -> Object
const { tagged } = require("styp");
const Point = tagged("Point", ["x","y"]);
let p1 = Point.from({ x:10, y:3, extra:"anything" });
console.log(p1.toString()); // -> Point(10,3)
Instances
Every instance created by a constructor function is immutable. There is one predefined method toString
. More methods can be added to the prototype of the constructor function.
const { tagged } = require("styp");
const Point = tagged("Point", ["x","y"]);
console.log(Point(5,5).toString()); // -> Point(5,5)
Point.prototype.scale = function(n) {
return Point(this.x*n,this.y*n);
}
console.log(Point(5,5).scale(2).toString()); // -> Point(10,10)
There is special method accessible on instances of constructors belonging to sum types - cata
const { sum } = require("styp");
const Point = sum("Point", {
Cartesian: ["x","y","z"],
Polar: ["r","theta"]
});
let p1 = Point.Cartesian(2,3);
let p2 = Point.Polar(1,5);
let doSomething = (point) => point.cata({
Cartesian: c => c.x,
Polar: p => p.r
});
console.log(doSomething(p1)); // -> 2
console.log(doSomething(p2)); // -> 1