npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

lambdash

v0.7.0-alpha.5

Published

Generic functional programming for javascript

Downloads

11

Readme

Lambdash

Lambdash is a library for generic functional programming in JavaScript.

Lamdash enables you to create custom data types that are on equal footing with the types built into the javascript language. It also enables you to write your code in a point-free, functional style.

The library is built on two concepts: modules, and interfaces (aka typeclasses). Every value has a module. This is almost always the value's constructor. A module provides all the functions that operate on a type.

An interface defines a set of operations that must be implemented by a module for a type. Typically, implementing an interface allows for other operations to be performed on the value. The idea is that a little effort can result in a large payoff in terms of the functionality that lambdash can provide for your types.

Lamdash attempts to provide a mostly pure functional api. This includes curried functions and operations that do not modify the values they operate on (immutability).

Contents

Interfaces

Lambdash defines several standard interfaces (a.k.a. type classes) for custom and built in types. These interfaces allow generic functions to operate on implementing types in a manner specific to the data type being operated on. In general, these interfaces mirror the standard type classes in Haskell, though many functions are renamed to those more familiar to JavaScript.

Eq

Eq is an interface which defines equality between items of the same type. In particular, it is intended to test for structural equality.

Minimal Implementation

  1. eq: a -> a -> Boolean

Derived Functions

  1. neq: a -> a -> Boolean

Examples

var arr1 = [1,2,3];
var arr2 = [1,2,3];
var arr3 = [1,2,3,4];

_.eq(arr1, arr2);  // true
_.neq(arr1, arr2); // false

_.eq(arr1, arr3);  // false
_.neq(arr1, arr3); // true

Ord

Ord is an interface for the ordering of elements.

To facilitate ordering, Lambdash provides an algebraic data type for ordering called Ordering.

// represents a "less than result"
_.Ordering.LT === _.LT

// represents a "greater than result"
_.Ordering.GT === _.GT

// represents an "equal to result"
_.Ordering.EQ === _.EQ

Types that implement Ord must also implement Eq.

Minimal Implementation

  1. compare: a -> a -> Ordering

Derived Functions

  1. lt: a -> a -> Boolean
  2. gt: a -> a -> Boolean
  3. lte: a -> a -> Boolean
  4. gte: a -> a -> Boolean
  5. min: a -> a -> a
  6. max: a -> a -> a

Examples

_.compare(1, 2);             // _.LT
_.compare('cat', 'cab');     // _.GT
_.compare([1,2,3], [1,2,3]); // _.EQ

_.lt(1, 2);             // true
_.gt('boat', 'coat');   // false

_.min(43, 56);          // 43
_.max([1,2,3], [1,2,4]) // [1,2,4]

Bounded

Bounded is an interface for types that have a maximum and minimum bound

Minimal Implementation

  1. minBound: () -> a
  2. maxBound: () -> a

Derived Functions

  1. isMin: a -> Boolean
  2. isMax: a -> Boolean

Additionally, the generic _.minBound and _.maxBound functions accepts a value and return the minBound and maxBound for the values type, respectively.

Examples

_.isMin(false);    // true
_.isMin(true);     // false

_.isMax(false);    // false
_.isMax(true);     // true

_.minBound(true);  // false
_.maxBound(true);  // true

Enum

The Enum interface is for types whose values are enumerable. In particular, implementing values may be converted to and from an integer in a consistent fashion.

Values which implement Enum may or may not also implement Bounded.

Minimal implementation

  1. toInt: a -> Integer
  2. fromInt: Integer -> a

Derived Functions

  1. prev: a -> a
  2. next: a -> a
  3. enumTo: a -> a -> Array a
  4. enumUntil: a -> a -> Array a
  5. enumFrom: Integer -> a -> Array a

Examples

_.enumTo(1,5);         // [1,2,3,4,5]
_.enumUntil(1,5);      // [1,2,3,4]

_.enumTo(5,1);         // [5,4,3,2,1]
_.enumUntil(5,1);      // [5,4,3,2]

_.enumTo('A', 'E');    // ['A','B','C','D','E']
_.enumTo(true, false); // [true,false]

_.enumFrom(4, 'D');    // ['D','E','F','G']
_.enumFrom(-3, 'Q');   // ['Q','P','O']

_.enumFrom(2)('r');    // ['r','s']
_.enumFrom(_,2)(3);    // [2,3,4]

Numeric

The Numeric interface is for types upon whose values algebraic operations can be performed.

Minimal Implementation

  1. toNum -> a -> Number
  2. fromNum -> Number -> a

Optional Function Implementations

The following functions may be provided for optimization. If they are not provided, operations, in most cases, are performed by first converting the value to a number then back to the type. It is highly recommended that these functions are implemented rather than relying on the default behavior.

  1. add: a -> a -> a
  2. sub: a -> a -> a
  3. mul: a -> a -> a
  4. div: a -> a -> a
  5. mod: a -> a -> a
  6. abs: a -> a
  7. sign: a -> a
  8. negate: a -> a
  9. reciprocal: a -> a
  10. pow: a -> a -> a

Derived Functions

  1. subBy: a -> a -> a
  2. divBy: a -> a -> a
  3. modBy: a -> a -> a
  4. powBy: a -> a -> a

Functor

A functor is a mappable, structure preserving type.

A functor should conform to the following law:

_.map(_.identity, a) is equal to a
_.map(f, _.map(g, a)) is equal to _.map(_.compose(f,g), a)

Minimal Implementation

  1. map: Functor f => (a -> b) -> f a -> f b

Example

_.map(x => x + 1, [1,2,3]);   // [2,3,4]

Semigroup

A semigroup is a type that whose values can be concatenated together. The following law should be observed:

_.concat(a, _.concat(b, c)) is equal to _.concat(_.concat(a, b), c)

Minimal Implementation

  1. concat: a -> a -> a

Derived Functions

  1. concatAll: a... -> a

Examples

_.concatAll([1,2],[3,4],[5,6]);  // [1,2,3,4,5,6]

_.concat([1,2],[3,4]);           // [1,2,3,4]
_.concat([1,2])([3,4]);          // [1,2,3,4]
_.concat(_,[1,2])([3,4]);        // [3,4,1,2]

Monoid

A type that implements Monoid must also implement Semigroup

A Monoid is a semigroup with an empty value. It must confrom to the following law:

_.concat(_.empty(a), a) is equal to _.concat(a, _.empty(a)) is equal to a

Minimal Implementation

  1. empty: () -> a

Derived Functions

  1. isEmpty: a -> Boolean
  2. cycleN: Number -> m -> m

Additionally, the generic _.empty function accepts a value and returns the empty value for the type.

Examples

_.empty([1,2,3]);     // []
_.empty("string");    // ""

_.isEmpty([1,2,3]);   // false
_.isEmpty([]);        // true

_.cycleN(3, [1,2,3]); // [1,2,3,1,2,3,1,2,3];
_.cycleN(4, ["ab"]);  // "abababab"

Applicative

A type that implements applicative may have values which may be applied to other values of the type.

A value that implements Applicative must first implement Functor.

The following should be true:

A.ap(A.of(f),A.of(a)) is equal to A.map(f, A.of(a))

Minimal Implementation

  1. ap: Applicative p => p (a -> b) -> p a -> p b
  2. of: Applicative p => a -> p a

Examples

_.ap(_.Arr.of(x => x + 1), [1,2,3]);      // [2,3,4]
_.ap([x => x + 1, x => x * 2], [1,2,3]);  // [2,3,4,2,4,6]

Monad

A monad is a chainable container type.

A type that implements Monad must first implement Applicative

Minimal Implementation

  1. flatten: Monad m => m (m a) -> m a

Optional Function Implementations

  1. chain: Monad m => (a -> m b) -> m a -> m b

Additionally, functions that operate on monads may be composed or piped using the _.composeM and _.pipeM functions. These functions behave in a similar manner to _.compose and _.pipe except that the functions are joined with the _.chain function.

Examples


    var Maybe = require('lambdash.maybe'),
        Just = Maybe.Just,
        None = Maybe.None;

    _.flatten(Just(Just(1)));       // Just(1)
    _.flatten(Just(None));          // None
    _.flatten(None);                // None

    _.flatten([[1,2],[3,4],[5,6]]);        // [1,2,3,4,5,6]

    _.chain(n => [n, n * 2], [1,2,3]);     // [1,2,2,4,3,6]

    var add1 = x => [_.add(x,1)];
    var mul2 = x => [_.mul(x,2)];
    var sub2 = x => [_.sub(x,2)];

    var composed = _.composeM(add1, mul2, sub2);
    composed([3,4,5]);                     // [3,5,7]

    var piped = _.pipeM(add1, mul2, sub2);
    piped([3,4,5]);                        // [6,8,10]

Foldable

The Foldable interface is for container types that can be folded into a value.

Minimal Implementation

  1. foldl: Foldable f => (b -> a -> b) -> b -> f a -> b
  2. foldr: Foldable f => (b -> a -> b) -> b -> f a -> b

Derived Functions

  1. foldMap: (Foldable f, Monoid m) => (a -> m) -> f a -> m
  2. foldMap2Def: (Foldable f, Monoid m) => (a -> m) -> m -> f a -> m
  3. join: (Foldable f, Monoid m) => f m -> m
  4. joinDef: (Foldable f, Monoid m) => m -> f m -> m
  5. joinWith: (Foldable f, Monoid m) => m -> f m -> m
  6. joinWithDef: (Foldable f, Monoid m) => m -> m -> f m -> m
  7. toArray: Foldable f => f a -> Array a
  8. len: Foldable f => f a -> Integer
  9. isEmpty: Foldable f => f a -> Boolean
  10. isNotEmpty: Foldable f => f a -> Boolean
  11. contains: (Foldable f, Eq a) => a -> f a -> Boolean
  12. notContains: (Foldable f, Eq a) => a -> f a -> Boolean
  13. any: Foldable f => (a -> Boolean) -> f a -> Boolean
  14. all: Foldable f => (a -> Boolean) -> f a -> Boolean
  15. countWith: Foldable f => (a -> Boolean) -> f a -> Number
  16. count: (Foldable f, Eq e) => e -> f e -> Number
  17. fold1: Foldable f => (b -> a -> b) -> f a -> b
  18. foldl1: Foldable f => (b -> a -> b) -> f a -> b
  19. foldr1: Foldable f => (b -> a -> b) -> f a -> b
  20. maximum: (Foldable f, Ord a) => f a -> a
  21. minimum: (Foldable f, Ord a) => f a -> a
  22. sum: (Foldable f, Numeric a) => f a -> a
  23. product: (Foldable f, Numeric a) => f a -> a

Sequential

The Sequential interface is for containers whose values are ordered and indexable.

A type that implements Sequential must first implement Foldable and Monoid.

Minimal Implementation

  1. nth: Sequential s => Number -> s a -> a
  2. of: Sequential s => a -> s a

Optional Function Implementations

  1. len: Sequential s => s -> Number
  2. append: Sequential s => a -> s a -> s a
  3. prepend: Sequential s => a -> s a -> s a
  4. slice: Sequential s => Number -> Number -> s a -> s a
  5. intersperse: Sequential s => a -> s a -> s a
  6. reverse: Sequential s => s a -> s a
  7. filter: Sequential s => (a -> Boolean) -> s a -> s a
  8. uniqueBy: Sequential s => (a -> b) -> s a -> s a
  9. findIndex: Sequential s => (a -> Boolean) -> s a -> Number
  10. findLastIndex: Sequential s => (a -> Boolean) -> s a -> Number

Derived Functions

  1. take: Sequential s => Number -> s a -> s a
  2. drop: Sequential s => Number -> s a -> s a
  3. takeLast: Sequential s => Number -> s a -> s a
  4. dropLast: Sequential s => Number -> s a -> s a
  5. head: Sequential s => s a -> a
  6. last: Sequential s => s a -> a
  7. tail: Sequential s => s a -> s a
  8. init: Sequential s => s a -> s a
  9. splitAt: Sequential s => Number -> s a -> Array (s a)
  10. takeWhile: Sequential s => (a -> Boolean) -> s a -> s a
  11. dropWhile: Sequential s => (a -> Boolean) -> s a -> s a
  12. takeLastWhile: Sequential s => (a -> Boolean) -> s a -> s a
  13. dropLastWhile: Sequential s => (a -> Boolean) -> s a -> s a
  14. unique: Sequential s => s a -> s a
  15. find: Sequential s => (a -> Boolean) -> s a -> a
  16. findLast: Sequential s => (a -> Boolean) -> s a -> a
  17. indexOf: Sequential s => a -> s a -> Number
  18. lastIndexOf: Sequential s => a -> s a -> Number

SetOps

SetOps is an interface for performing common set operations on

Minimal Implementation

  1. union: SetOps s => s -> s -> s
  2. difference: SetOps s => s -> s -> s
  3. intersection: SetOps s => s -> s -> s
  4. symmetricDifference: SetOps s => s -> s -> s

Derived Functions

There are none.

Set

Set is an interface for a collection of (logical) unique values.

A type that implements set must also implement SetOps.

Minimal Implementation

  1. exists: Set s => k -> s k -> Boolean
  2. insert: Set s => k -> s k -> s k
  3. remove: Set s => k -> s k -> s k

Derived Functions

There are none.

Associative

The Associative interface is for containers that map keys to values.

Minimal Implementation

  1. assoc: Associative a => k -> v -> a k v -> a k v
  2. dissoc: Associative a => k -> a k v -> a k v
  3. exists: Associative a => k -> a k v -> Boolean
  4. lookup: Associative a => k -> a k v -> v

Optional Functions

These functions may be implemented, but they are not required nor are they derived.

  1. keys: Associative a => a k v -> Array k
  2. values: Associative a => a k v -> Array v
  3. mapAssoc: Associative a => (v -> k -> v) -> a k v -> a k v
  4. foldlAssoc: Associative a => (b -> v -> k -> b) -> b -> a k v -> b
  5. foldrAssoc: Associative a => (b -> v -> k -> b) -> b -> a k v -> b
  6. filterAssoc: Associative a => (v -> k -> Boolean) -> a k v -> a k v

Derived Functions

  1. lookupAll: (Functor f, Associative a) => f k -> a k v -> f v
  2. lookupOr: Associative a => v -> k -> a k v -> v
  3. update: Associative a => k -> (v -> v) -> a k v -> a k v
  4. updateOr: Associative a => v -> k -> (v -> v) -> a k v -> a k v

Additionally, if the type implements foldlAssoc the following is derived:

  1. pairs: Associative a => a k v -> Array Array(k,a))

Show

The show type is for converting a datatype to a string representation.

Minimal Implementation

  1. show: Show s => s -> String

Modules For Built-in Types

Lambdash provides a module for most of the built-in types. If one is not provided, it the Obj module is the default. All of the functions listed for each module are attached to the root lambdash object.

Any

The any type can be any value. It exists for validation when creating algebraic data types.

Implements

Nothing.

Functions

None.

Bool

The Bool module is for Boolean values.

Implements

  1. Eq
  2. Ord
  3. Enum
  4. Show

Functions

  1. and: Boolean -> Boolean -> Boolean
  2. or: Boolean -> Boolean -> Boolean
  3. xor: Boolean -> Boolean -> Boolean
  4. not: Boolean -> Boolean
  5. both: (*... -> Boolean) -> (*... -> Boolean) -> (*... -> Boolean)
  6. either: (*... -> Boolean) -> (*... -> Boolean) -> (*... -> Boolean)
  7. neither: (*... -> Boolean) -> (*... -> Boolean) -> (*... -> Boolean)
  8. eitherExclusive: (*... -> Boolean) -> (*... -> Boolean) -> (*... -> Boolean)
  9. complement: (*... -> Boolean) -> (*... -> Boolean)
  10. condition: [(*... -> Boolean), (*... -> a)]... -> (*... -> a)
  11. T: () -> Boolean
  12. F: () -> Boolean

Num

The Num module is for Number values.

Implements

  1. Eq
  2. Ord
  3. Enum
  4. Numeric
  5. Show

Functions

No additional functions.

Int

The Int module is only meant to act as a constraint for numbers that should always be integral. Currently a number will always use the Num module for its functionality.

Implements

Nothing

Functions

No additional functions.

Str

The Str module is for string values.

Implements

  1. Eq
  2. Ord
  3. Enum (uses the first character of the string)
  4. Functor
  5. Semigroup
  6. Monoid
  7. Foldable
  8. Sequential
  9. Show

Functions

  1. split: String|RegExp -> String -> Array String
  2. match: RegExp -> String -> Array String
  3. replace: String|RegExp -> String -> String -> String
  4. toLower: String -> String
  5. toUpper: String -> String
  6. trim: String -> String
  7. lines: String -> Array String
  8. words: String -> Array String
  9. unlines: Foldable f => f String -> String
  10. unwords: Foldable f => f String -> String

Arr

Arr is the lambdash module for Arrays.

Implements

  1. Eq (if its elements implement Eq)
  2. Ord (if its elements implement Ord)
  3. Functor
  4. Foldable
  5. Semigroup
  6. Monoid
  7. Applicative
  8. Monad
  9. Sequential
  10. SetOps
  11. Set
  12. Show (if its elements implement Show)

Functions

  1. applyTo: (* -> *) -> Array * -> *

Obj

Object is the lambdash module for objects.

Implements

  1. Eq (if its values implement Eq)
  2. Ord (if its values implement Ord)
  3. Functor
  4. Semigroup (concat is a right biased union)
  5. Monoid
  6. SetOps
  7. Foldable
  8. Associative (with optional functions)
  9. Show (if its values implement Show, keys are sorted)

Functions

  1. copy: {String: a} -> {String: a}
  2. copyOwn: {String: a} -> {String: a}
  3. propExists: String -> {String: a} -> Boolean
  4. ownPropExists: String -> {String: a} -> Boolean
  5. prop: String -> {String: a} -> a|undefined
  6. propOr: a -> String -> {String: a} -> a
  7. props: Foldable f => f String -> {String: a} -> f a
  8. propNames: {String: a} -> [String]
  9. ownPropNames: {String: a} -> [String]
  10. ownValues: {String: a} -> [a]
  11. ownPairs: {String: a} -> [[String, a]]
  12. filter: (a -> Boolean) -> {String: a} -> {String: a}

Regex

Regex is the lambdash module for regular expression objects.

Implements

  1. Show

Functions

  1. test: String -> RegExp -> Boolean
  2. exec: String -> RegExp -> [String]

Notes

A 3rd-party package could be created to extend this functionality.

DT

DT is the lambdash module for DateTime objects.

Implements

  1. Eq
  2. Ord
  3. Numeric
  4. Show

Functions

None.

Notes

A 3rd-party package should be created to extend this functionality.

Fun

Fun is the lambdash module for Functions.

Implements

Nothing.

Functions

  1. compose: (*... -> *)... -> (*... -> *)
  2. pipe: (*... -> *)... -> (*... -> *)
  3. always: a -> (() -> a)
  4. alwaysThrow: (*... -> Error) -> *... -> (() -> ())
  5. thunk: (*... -> *) -> *... -> (() -> *)
  6. identity: a -> a
  7. curry: (*...-> *) -> (*... -> *)
  8. curryN: Number -> (*... -> *) -> (*... -> *)
  9. arity: Number -> (*... -> *) -> (*... -> *)
  10. make: String -> (*... -> *) -> (*... -> *)
  11. thisify: (*... -> *) -> (*... -> *)
  12. liftN: Applicative a => -> Number -> (*... -> c) -> ((a *)... -> a c)
  13. lift: (*... -> c) -> ((a *)... -> a c)
  14. apply: Foldable f => f * -> (*... -> a) -> a
  15. noop: () -> ()
  16. flip: ``

Unit

Unit is the module for undefined and null values.

Implements

  1. Eq (always true)
  2. Ord (always EQ)
  3. Semigroup (always null)
  4. Monoid
  5. Functor (always null)
  6. Show

Functions

None

The future

The library does not yet support ECMAScript 2015 types. There are plans for adding support for them.

Creating Types

Lambdash provides a way to declare new algebraic data types. It also provides a mechanism that will make lambdash start treating your types as modules, which allows all of lambdash's generic functions to operate on your types instances.

Creating a Module

Lambdash does not all care about an objects prototype. Instead, it cares about modules. Every object has module. For custom types, by default, this module is lamdash's Obj module. However, the whole point of the library is to allow the user the ability to create their own types which will have an equal status with all the other types.

Lamdash provides a function, _.Type.moduleFor, which will return the module for a value. The following is the process through which the module is identified:

  1. If the value is null or undefined, return the Unit module
  2. If the values constructor is a module and a submodule, return the constructor's parent module.
  3. If the values constructor is a module, return the constructor
  4. Return the appropriate module for built-in types.

A type can be declared as a module using the _.Type.module function.


// this example uses a constructor function since it is an easy
// way to set a constructor for a value
function Example(x) {
    this.whatever = x
}

var ex = new Example(1);

_.Type.moduleFor(ex);   // _.Type.Obj

// make Example a module
_.Type.module(Example);
_.Type.ModuleFor(ex);  // Example

Submodules can be defined with the _.Type.subModule function.
The first parameter is the parent module, the second is the submodule. The submodule should also be declared as a module. This functionality exists for sum types.

Modules will probably also want to add a member function. The member function should accept a single value and return true if the value is a member of the type, false if not.

Product Types

Lamdash has a way to create product types. A product type is a type that has a fixed number of labelled or non-labelled elements.

Product types are automatically created as modules.

A Product type should specify a name as its first argument and a definition as its second argument. The definition may be an object or an array. If the definition is an object, the keys will be the fields of the product type and the values will be constraints. If the definition is an array, its values should be constraints.

Constraints may be a type with a member function, a function that accepts a value and returns true or false, or null. If the constraint is null, the value may be of any type, but must be defined.

Every product type will automatically implement Eq (assuming its field implement Eq). They will also have an unapply function.


var Point = _.Type.product('Point', {x: _.Num, y: _.Num});

var p = Point(1,2);
p instanceof Point;  // true
_.Type.moduleFor(p); // Point
Point.name;          // "Point"
Point.member(point); // true

p.x;  // 1
p.y;  // 2
p[0]; // 1
p[1]; // 2

var p2 = Point('a', 'b'); // TypeError

// with an array
var Point = _.Type.product('Point', [_.Num, _.Num]);

p._0;  // 1
p._1;  // 2
p[0]; // 1
p[1]; // 2

_.eq(Point(1,2), Point(1,2)); // true
_.eq(Point(1,2), Point(1,3)); // false

_.unapply(function(x,y){console.log('x:'+x+',y:',y)}, p);  // 'x:1,y:2'

Every product type will automatically implement Eq (assuming its field implement Eq). They will also have an unapply function.

Sum Types

Sum types are a type that can be an instance of any one of its sub types.

To create a sum type pass a name as a string or a named function as the first parameter, and a definition object to the second parameter of the _.Type.sum function. The definition must be an object with the keys as the names of the subtypes, and the values as product type definitions. The keys must be valid identifier names.

If a definition of a subtype is empty, a single instance will be created and attached to the sum type rather than the constructor.

Every sum type will implement Eq and will also have a case function which can be use for simple matching of the type of the value.


var Maybe = _.Type.sum('Maybe', {'None': [], 'Some': {value: _.Any}});

var maybe = Maybe.None;
maybe instancof Maybe;  // true
Maybe.member(maybe);    // true

_.Type.moduleFor(maybe); // Maybe

maybe = Maybe.Some(1);
maybe instanceof Maybe;      // true
maybe instanceof Maybe.Some; // true
Maybe.member(maybe);         // true

var value = _.case({
    None: 0,
    Some: function(v) {
        return v + 1;
    }
}, maybe);
// value is 2

// case with a default
value = _.case({
    None: 1,
    _: 0
}, maybe);
// value is 0

// creating maybe with a function
var Maybe = function(value) {return value == null ? Maybe.None : Maybe.Some(value) }
Maybe = _.Type.sum(Maybe, {'None': [], 'Some': {value: _.Any}});

Maybe(1);    // Some(1)
Maybe(null); // None

Enumerated Types

Enumerated types are a special case of Sum types in which there are no values associated with any of the sub types.

Enumerated types will automatically implement Ord, Bounded, and Enum.


var Days = _.Type.enumerated('Days', ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']);

_.enumFrom(Days.Tue, Days.Fri); // [Tue, Wed, Thu, Fri]
_.lt(Days.Tue, Days.Thu);       // true

Days.maxBound();   // 'Sun'
Days.minBound();   // 'Mon'

Implementing Interfaces

Custom types may implement interfaces by creating the correct functions.

For example, consider implementing functor for the maybe type.
The functor interface requires that the type implement Map.


var Maybe = _.Type.sum('Maybe', {None: [], Some: {value: _.Any}});

var m = Maybe.Some(1);

_.Functor.member(m);  // false

Maybe.map = _.curry(function(fn, maybe){
    if (maybe === Maybe.None) {
        return maybe;
    }
    return Maybe.Some(fn(maybe.value));
});

_.Functor.member(m);         // true

_.map(_.add(2), m);          // Some(3)
_.map(_.add(2), Maybe.None); // None

Roadmap

I feel that the 0.6.0 release is very significant release. It is the first release that I actually feel comfortable using in a real application.

That being said, there is more work to do.

After the 0.6.0 release, I intend on improving the workflow.
The master branch will always contain the most recent stable release and development will take place in other branches.

Plans For Next Release

The following is either planned or under review for the 0.7.0 release.

  1. Implement modules for the new ECMAScript 2015 types
  2. Figure out what to do with the Int module and what exactly its role in the library is
  3. Adding Unicode processing functions to the Str module
  4. Possibly adding a way to create a Union type (like a sum type from existing types)
  5. Improve and further standardize docblocks and generate api docs

Eventual Plans

  1. Create a script that will amalgamate the files into one and minimize for the browser.
  2. Create benchmarks.
  3. Create a website for the library.
  4. Create an external module that will improve or replace the DT module.

Additional Libraries

Additional libraries for lambdash are either available or under development.

  1. Task (For asynchronous computations)
  2. List
  3. Maybe
  4. Either

If you have developed an additional library for lamdash, please let me know so that I can list it here.

Contributing

I am happy to take pull requests If anybody wants to contribute.

Tests

To run tests:

npm install --dev
npm test

To run the coverage report:

npm run coverage