Comparing version 0.4.0 to 0.5.0
1125
index.js
@@ -11,2 +11,55 @@ /* ####### | ||
//. # Sanctuary | ||
//. | ||
//. Sanctuary is a small functional programming library inspired by Haskell | ||
//. and PureScript. It depends on and works nicely with [Ramda][]. Sanctuary | ||
//. makes it possible to write safe code without null checks. | ||
//. | ||
//. In JavaScript it's trivial to introduce a possible run-time type error: | ||
//. | ||
//. words[0].toUpperCase() | ||
//. | ||
//. If `words` is `[]` we'll get a familiar error at run-time: | ||
//. | ||
//. TypeError: Cannot read property 'toUpperCase' of undefined | ||
//. | ||
//. Sanctuary gives us a fighting chance of avoiding such errors. We might | ||
//. write: | ||
//. | ||
//. R.map(R.toUpper, S.head(words)) | ||
//. | ||
//. ## Types | ||
//. | ||
//. Sanctuary uses Haskell-like type signatures to describe the types of | ||
//. values, including functions. `'foo'`, for example, has type `String`; | ||
//. `[1, 2, 3]` has type `[Number]`. The arrow (`->`) is used to express a | ||
//. function's type. `Math.abs`, for example, has type `Number -> Number`. | ||
//. That is, it takes an argument of type `Number` and returns a value of | ||
//. type `Number`. | ||
//. | ||
//. [`R.map`][R.map] has type `(a -> b) -> [a] -> [b]`. That is, it takes | ||
//. an argument of type `a -> b` and returns a value of type `[a] -> [b]`. | ||
//. `a` and `b` are type variables: applying `R.map` to a value of type | ||
//. `String -> Number` will give a value of type `[String] -> [Number]`. | ||
//. | ||
//. Sanctuary embraces types. JavaScript doesn't support algebraic data types, | ||
//. but these can be simulated by providing a group of constructor functions | ||
//. whose prototypes provide the same set of methods. A value of the Maybe | ||
//. type, for example, is created via the Nothing constructor or the Just | ||
//. constructor. | ||
//. | ||
//. It's necessary to extend Haskell's notation to describe implicit arguments | ||
//. to the *methods* provided by Sanctuary's types. In `x.map(y)`, for example, | ||
//. the `map` method takes an implicit argument `x` in addition to the explicit | ||
//. argument `y`. The type of the value upon which a method is invoked appears | ||
//. at the beginning of the signature, separated from the arguments and return | ||
//. value by a squiggly arrow (`~>`). The type of the `map` method of the Maybe | ||
//. type is written `Maybe a ~> (a -> b) -> Maybe b`. One could read this as: | ||
//. | ||
//. _When the `map` method is invoked on a value of type `Maybe a` | ||
//. (for any type `a`) with an argument of type `a -> b` (for any type `b`), | ||
//. it returns a value of type `Maybe b`._ | ||
//. | ||
//. ## API | ||
;(function() { | ||
@@ -16,20 +69,15 @@ | ||
var hasOwnProperty_ = Object.prototype.hasOwnProperty; | ||
var slice_ = Array.prototype.slice; | ||
var toString_ = Object.prototype.toString; | ||
var R; | ||
var S = {}; | ||
var isArray = function(x) { | ||
return toString_.call(x) === '[object Array]'; | ||
}; | ||
/* istanbul ignore else */ | ||
if (typeof module !== 'undefined') { | ||
R = require('ramda'); | ||
module.exports = S; | ||
} else { | ||
R = this.R; | ||
this.sanctuary = S; | ||
} | ||
var curry = function(f) { | ||
var arity = f.length; | ||
var recurry = function(args) { | ||
return function() { | ||
var args2 = args.concat(slice_.call(arguments)); | ||
return args2.length >= arity ? f.apply(this, args2) : recurry(args2); | ||
}; | ||
}; | ||
return recurry([]); | ||
}; | ||
var _ = R.__; | ||
@@ -45,9 +93,57 @@ var extend = function(Child, Parent) { | ||
// maybe ///////////////////////////////////////////////////////////////// | ||
var filter = function(pred, m) { | ||
return m.chain(function(x) { | ||
return pred(x) ? m.of(x) : m.empty(); | ||
}); | ||
}; | ||
function Maybe() { | ||
//. ### Combinator | ||
//# K :: a -> b -> a | ||
//. | ||
//. The K combinator. Takes two values and returns the first. Equivalent to | ||
//. Haskell's `const` function. | ||
//. | ||
//. ```javascript | ||
//. > S.K('foo', 'bar') | ||
//. "foo" | ||
//. > R.map(S.K(42), R.range(0, 5)) | ||
//. [42, 42, 42, 42, 42] | ||
//. ``` | ||
S.K = R.curry(function(x, y) { | ||
return x; | ||
}); | ||
//. ### Maybe type | ||
//# Maybe :: Type | ||
//. | ||
//. The Maybe type represents optional values: a value of type `Maybe a` is | ||
//. either a Just whose value is of type `a` or a Nothing (with no value). | ||
//. | ||
//. The Maybe type satisfies the [Monoid][] and [Monad][] specifications. | ||
var Maybe = S.Maybe = function Maybe() { | ||
throw new Error('Cannot instantiate Maybe'); | ||
} | ||
}; | ||
// Maybe.of :: a -> m a | ||
//# Maybe.empty :: -> Maybe a | ||
//. | ||
//. Returns a Nothing. | ||
//. | ||
//. ```javascript | ||
//. > S.Maybe.empty() | ||
//. Nothing() | ||
//. ``` | ||
Maybe.empty = function() { | ||
return new Nothing(); | ||
}; | ||
//# Maybe.of :: a -> Maybe a | ||
//. | ||
//. Takes a value of any type and returns a Just with the given value. | ||
//. | ||
//. ```javascript | ||
//. > S.Maybe.of(42) | ||
//. Just(42) | ||
//. ``` | ||
Maybe.of = function(x) { | ||
@@ -57,24 +153,200 @@ return new Just(x); | ||
//# Maybe#ap :: Maybe (a -> b) ~> Maybe a -> Maybe b | ||
//. | ||
//. Takes a value of type `Maybe a` and returns a Nothing unless `this` | ||
//. is a Just *and* the argument is a Just, in which case it returns a | ||
//. Just whose value is the result of of applying this Just's value to | ||
//. the given Just's value. | ||
//. | ||
//. ```javascript | ||
//. > S.Nothing().ap(S.Just(42)) | ||
//. Nothing() | ||
//. | ||
//. > S.Just(R.inc).ap(S.Nothing()) | ||
//. Nothing() | ||
//. | ||
//. > S.Just(R.inc).ap(S.Just(42)) | ||
//. Just(43) | ||
//. ``` | ||
//# Maybe#chain :: Maybe a ~> (a -> Maybe b) -> Maybe b | ||
//. | ||
//. Takes a function and returns `this` if `this` is a Nothing; otherwise | ||
//. it returns the result of applying the function to this Just's value. | ||
//. | ||
//. ```javascript | ||
//. > S.Nothing().chain(S.parseFloat) | ||
//. Nothing() | ||
//. | ||
//. > S.Just('xxx').chain(S.parseFloat) | ||
//. Nothing() | ||
//. | ||
//. > S.Just('12.34').chain(S.parseFloat) | ||
//. Just(12.34) | ||
//. ``` | ||
//# Maybe#concat :: Maybe a ~> Maybe a -> Maybe a | ||
//. | ||
//. Returns the result of concatenating two Maybe values of the same type. | ||
//. `a` must have a [Semigroup][] (indicated by the presence of a `concat` | ||
//. method). | ||
//. | ||
//. If `this` is a Nothing and the argument is a Nothing, this method returns | ||
//. a Nothing. | ||
//. | ||
//. If `this` is a Just and the argument is a Just, this method returns a | ||
//. Just whose value is the result of concatenating this Just's value and | ||
//. the given Just's value. | ||
//. | ||
//. Otherwise, this method returns the Just. | ||
//. | ||
//. ```javascript | ||
//. > S.Nothing().concat(S.Nothing()) | ||
//. Nothing() | ||
//. | ||
//. > S.Just([1, 2, 3]).concat(S.Just([4, 5, 6])) | ||
//. Just([1, 2, 3, 4, 5, 6]) | ||
//. | ||
//. > S.Nothing().concat(S.Just([1, 2, 3])) | ||
//. Just([1, 2, 3]) | ||
//. | ||
//. > S.Just([1, 2, 3]).concat(S.Nothing()) | ||
//. Just([1, 2, 3]) | ||
//. ``` | ||
//# Maybe#empty :: Maybe a ~> Maybe a | ||
//. | ||
//. Returns a Nothing. | ||
//. | ||
//. ```javascript | ||
//. > S.Just(42).empty() | ||
//. Nothing() | ||
//. ``` | ||
Maybe.prototype.empty = Maybe.empty; | ||
//# Maybe#equals :: Maybe a ~> Maybe a -> Boolean | ||
//. | ||
//. Takes a Maybe and returns `true` if: | ||
//. | ||
//. - it is a Nothing and `this` is a Nothing; or | ||
//. | ||
//. - it is a Just and `this` is a Just, and their values are equal, | ||
//. in [SameValue][] terms. | ||
//. | ||
//. ```javascript | ||
//. > S.Nothing().equals(S.Nothing()) | ||
//. true | ||
//. | ||
//. > S.Just(42).equals(S.Just(42)) | ||
//. true | ||
//. | ||
//. > S.Just(42).equals(S.Just(43)) | ||
//. false | ||
//. | ||
//. > S.Just(42).equals(S.Nothing()) | ||
//. false | ||
//. ``` | ||
//# Maybe#filter :: Maybe a ~> (a -> Boolean) -> Maybe a | ||
//. | ||
//. Takes a predicate and returns `this` if `this` is a Just whose value | ||
//. satisfies the predicate; Nothing otherwise. | ||
//. | ||
//. ```javascript | ||
//. > S.Just(42).filter(function(n) { return n % 2 === 0; }) | ||
//. Just(42) | ||
//. | ||
//. > S.Just(43).filter(function(n) { return n % 2 === 0; }) | ||
//. Nothing() | ||
//. ``` | ||
Maybe.prototype.filter = function(pred) { | ||
return filter(pred, this); | ||
}; | ||
//# Maybe#map :: Maybe a ~> (a -> b) -> Maybe b | ||
//. | ||
//. Takes a function and returns `this` if `this` is a Nothing; otherwise | ||
//. it returns a Just whose value is the result of applying the function to | ||
//. this Just's value. | ||
//. | ||
//. ```javascript | ||
//. > S.Nothing().map(R.inc) | ||
//. Nothing() | ||
//. | ||
//. > S.Just(42).map(R.inc) | ||
//. Just(43) | ||
//. ``` | ||
//# Maybe#of :: Maybe a ~> b -> Maybe b | ||
//. | ||
//. Takes a value of any type and returns a Just with the given value. | ||
//. | ||
//. ```javascript | ||
//. > S.Nothing().of(42) | ||
//. Just(42) | ||
//. ``` | ||
Maybe.prototype.of = Maybe.of; | ||
//# Maybe#toBoolean :: Maybe a ~> Boolean | ||
//. | ||
//. Returns `false` if `this` is a Nothing; `true` if `this` is a Just. | ||
//. | ||
//. ```javascript | ||
//. > S.Nothing().toBoolean() | ||
//. false | ||
//. | ||
//. > S.Just(42).toBoolean() | ||
//. true | ||
//. ``` | ||
//# Maybe#toString :: Maybe a ~> String | ||
//. | ||
//. Returns the string representation of the Maybe. | ||
//. | ||
//. ```javascript | ||
//. > S.Nothing().toString() | ||
//. "Nothing()" | ||
//. | ||
//. > S.Just([1, 2, 3]).toString() | ||
//. "Just([1, 2, 3])" | ||
//. ``` | ||
//# Maybe#type :: Type | ||
//. | ||
//. A reference to the Maybe type. Useful for determining whether two | ||
//. values such as `S.Nothing()` and `S.Just(42)` are of the same type. | ||
Maybe.prototype.type = Maybe; | ||
function Nothing() { | ||
//# Nothing :: -> Maybe a | ||
//. | ||
//. Returns a Nothing. Though this is a constructor function the `new` | ||
//. keyword needn't be used. | ||
//. | ||
//. ```javascript | ||
//. > S.Nothing() | ||
//. Nothing() | ||
//. ``` | ||
var Nothing = S.Nothing = function Nothing() { | ||
if (!(this instanceof Nothing)) { | ||
return new Nothing(); | ||
} | ||
} | ||
}; | ||
extend(Nothing, Maybe); | ||
// Nothing#ap :: m a -> m b | ||
Nothing.prototype.ap = function(x) { // jshint ignore:line | ||
// Nothing#ap :: Maybe (a -> b) ~> Maybe a -> Maybe b | ||
Nothing.prototype.ap = function(x) { | ||
return this; | ||
}; | ||
// Nothing#chain :: (a -> m b) -> m b | ||
Nothing.prototype.chain = function(f) { // jshint ignore:line | ||
// Nothing#chain :: Maybe a ~> (a -> Maybe b) -> Maybe b | ||
Nothing.prototype.chain = function(f) { | ||
return this; | ||
}; | ||
// Nothing#equals :: Maybe a -> Boolean | ||
// Nothing#concat :: Maybe a ~> Maybe a -> Maybe a | ||
Nothing.prototype.concat = function(maybe) { | ||
return maybe; | ||
}; | ||
// Nothing#equals :: Maybe a ~> Maybe a -> Boolean | ||
Nothing.prototype.equals = function(maybe) { | ||
@@ -84,13 +356,28 @@ return maybe instanceof Nothing; | ||
// Nothing#or :: Maybe a -> Maybe a | ||
Nothing.prototype.or = function(maybe) { | ||
return maybe; | ||
// Nothing#map :: Maybe a ~> (a -> b) -> Maybe b | ||
Nothing.prototype.map = function(f) { | ||
return this; | ||
}; | ||
// Nothing#map :: (a -> b) -> Maybe b | ||
Nothing.prototype.map = function(f) { // jshint ignore:line | ||
return this; | ||
// Nothing#toBoolean :: Maybe a ~> Boolean | ||
Nothing.prototype.toBoolean = function() { | ||
return false; | ||
}; | ||
function Just(value) { | ||
// Nothing#toString :: Maybe a ~> String | ||
Nothing.prototype.toString = function() { | ||
return 'Nothing()'; | ||
}; | ||
//# Just :: a -> Maybe a | ||
//. | ||
//. Takes a value of any type and returns a Just with the given value. | ||
//. Though this is a constructor function the `new` keyword needn't be | ||
//. used. | ||
//. | ||
//. ```javascript | ||
//. > S.Just(42) | ||
//. Just(42) | ||
//. ``` | ||
var Just = S.Just = function Just(value) { | ||
if (!(this instanceof Just)) { | ||
@@ -101,6 +388,6 @@ return new Just(value); | ||
} | ||
} | ||
}; | ||
extend(Just, Maybe); | ||
// Just#ap :: m a -> m b | ||
// Just#ap :: Maybe (a -> b) ~> Maybe a -> Maybe b | ||
Just.prototype.ap = function(x) { | ||
@@ -110,3 +397,3 @@ return x.map(this.value); | ||
// Just#chain :: (a -> m b) -> m b | ||
// Just#chain :: Maybe a ~> (a -> Maybe b) -> Maybe b | ||
Just.prototype.chain = function(f) { | ||
@@ -116,13 +403,13 @@ return f(this.value); | ||
// Just#equals :: Maybe a -> Boolean | ||
Just.prototype.equals = function(maybe) { | ||
return maybe instanceof Just && maybe.value === this.value; | ||
// Just#concat :: Maybe a ~> Maybe a -> Maybe a | ||
Just.prototype.concat = function(maybe) { | ||
return maybe instanceof Just ? Just(this.value.concat(maybe.value)) : this; | ||
}; | ||
// Just#or :: Maybe a -> Maybe a | ||
Just.prototype.or = function(maybe) { // jshint ignore:line | ||
return this; | ||
// Just#equals :: Maybe a ~> Maybe a -> Boolean | ||
Just.prototype.equals = function(maybe) { | ||
return maybe instanceof Just && R.eqProps('value', maybe, this); | ||
}; | ||
// Just#map :: (a -> b) -> Maybe b | ||
// Just#map :: Maybe a ~> (a -> b) -> Maybe b | ||
Just.prototype.map = function(f) { | ||
@@ -132,4 +419,25 @@ return new Just(f(this.value)); | ||
// fromMaybe :: a -> Maybe a -> a | ||
var fromMaybe = curry(function(x, maybe) { | ||
// Just#toBoolean :: Maybe a ~> Boolean | ||
Just.prototype.toBoolean = function() { | ||
return true; | ||
}; | ||
// Just#toString :: Maybe a ~> String | ||
Just.prototype.toString = function() { | ||
return 'Just(' + R.toString(this.value) + ')'; | ||
}; | ||
//# fromMaybe :: a -> Maybe a -> a | ||
//. | ||
//. Takes a default value and a Maybe, and returns the Maybe's value | ||
//. if the Maybe is a Just; the default value otherwise. | ||
//. | ||
//. ```javascript | ||
//. > S.fromMaybe(0, S.Just(42)) | ||
//. 42 | ||
//. | ||
//. > S.fromMaybe(0, S.Nothing()) | ||
//. 0 | ||
//. ``` | ||
S.fromMaybe = R.curry(function(x, maybe) { | ||
switch (true) { | ||
@@ -145,10 +453,32 @@ case maybe instanceof Nothing: | ||
// toMaybe :: a? -> Maybe a | ||
var toMaybe = function(x) { | ||
return x == null ? Nothing() : Just(x); | ||
}; | ||
//# toMaybe :: a? -> Maybe a | ||
//. | ||
//. Takes a value and returns Nothing if the value is null or undefined; | ||
//. Just the value otherwise. | ||
//. | ||
//. ```javascript | ||
//. > S.toMaybe(null) | ||
//. Nothing() | ||
//. | ||
//. > S.toMaybe(42) | ||
//. Just(42) | ||
//. ``` | ||
S.toMaybe = R.ifElse(R.isNil, Nothing, Just); | ||
// encase :: (* -> a) -> (* -> Maybe a) | ||
var encase = function(f) { | ||
return function() { | ||
//# encase :: (* -> a) -> (* -> Maybe a) | ||
//. | ||
//. Takes a function `f` which may throw and returns a curried function | ||
//. `g` which will not throw. The result of applying `g` is determined by | ||
//. applying `f` to the same arguments: if this succeeds, `g` returns Just | ||
//. the result; otherwise `g` returns Nothing. | ||
//. | ||
//. ```javascript | ||
//. > S.encase(eval)('1 + 1') | ||
//. Just(2) | ||
//. | ||
//. > S.encase(eval)('1 +') | ||
//. Nothing() | ||
//. ``` | ||
var encase = S.encase = R.curry(function(f) { | ||
return R.curryN(f.length, function() { | ||
try { | ||
@@ -159,14 +489,181 @@ return Just(f.apply(this, arguments)); | ||
} | ||
}; | ||
}; | ||
}); | ||
}); | ||
// either //////////////////////////////////////////////////////////////// | ||
//. ### Either type | ||
function Either() { | ||
//# Either :: Type | ||
//. | ||
//. The Either type represents values with two possibilities: a value of type | ||
//. `Either a b` is either a Left whose value is of type `a` or a Right whose | ||
//. value is of type `b`. | ||
//. | ||
//. The Either type satisfies the [Semigroup][] and [Monad][] specifications. | ||
var Either = S.Either = function Either() { | ||
throw new Error('Cannot instantiate Either'); | ||
} | ||
}; | ||
//# Either.of :: b -> Either a b | ||
//. | ||
//. Takes a value of any type and returns a Right with the given value. | ||
//. | ||
//. ```javascript | ||
//. > S.Either.of(42) | ||
//. Right(42) | ||
//. ``` | ||
Either.of = function(x) { | ||
return new Right(x); | ||
}; | ||
//# Either#ap :: Either a (b -> c) ~> Either a b -> Either a c | ||
//. | ||
//. Takes a value of type `Either a b` and returns a Left unless `this` | ||
//. is a Right *and* the argument is a Right, in which case it returns | ||
//. a Right whose value is the result of applying this Right's value to | ||
//. the given Right's value. | ||
//. | ||
//. ```javascript | ||
//. > S.Left('Cannot divide by zero').ap(S.Right(42)) | ||
//. Left("Cannot divide by zero") | ||
//. | ||
//. > S.Right(R.inc).ap(S.Left('Cannot divide by zero')) | ||
//. Left("Cannot divide by zero") | ||
//. | ||
//. > S.Right(R.inc).ap(S.Right(42)) | ||
//. Right(43) | ||
//. ``` | ||
//# Either#chain :: Either a b ~> (b -> Either a c) -> Either a c | ||
//. | ||
//. Takes a function and returns `this` if `this` is a Left; otherwise | ||
//. it returns the result of applying the function to this Right's value. | ||
//. | ||
//. ```javascript | ||
//. > void (sqrt = function(n) { return n < 0 ? S.Left('Cannot represent square root of negative number') : S.Right(Math.sqrt(n)); }) | ||
//. undefined | ||
//. | ||
//. > S.Left('Cannot divide by zero').chain(sqrt) | ||
//. Left("Cannot divide by zero") | ||
//. | ||
//. > S.Right(-1).chain(sqrt) | ||
//. Left("Cannot represent square root of negative number") | ||
//. | ||
//. > S.Right(25).chain(sqrt) | ||
//. Right(5) | ||
//. ``` | ||
//# Either#concat :: Either a b ~> Either a b -> Either a b | ||
//. | ||
//. Returns the result of concatenating two Either values of the same type. | ||
//. `a` must have a [Semigroup][] (indicated by the presence of a `concat` | ||
//. method), as must `b`. | ||
//. | ||
//. If `this` is a Left and the argument is a Left, this method returns a | ||
//. Left whose value is the result of concatenating this Left's value and | ||
//. the given Left's value. | ||
//. | ||
//. If `this` is a Right and the argument is a Right, this method returns a | ||
//. Right whose value is the result of concatenating this Right's value and | ||
//. the given Right's value. | ||
//. | ||
//. Otherwise, this method returns the Right. | ||
//. | ||
//. ```javascript | ||
//. > S.Left('abc').concat(S.Left('def')) | ||
//. Left("abcdef") | ||
//. | ||
//. > S.Right([1, 2, 3]).concat(S.Right([4, 5, 6])) | ||
//. Right([1, 2, 3, 4, 5, 6]) | ||
//. | ||
//. > S.Left('abc').concat(S.Right([1, 2, 3])) | ||
//. Right([1, 2, 3]) | ||
//. | ||
//. > S.Right([1, 2, 3]).concat(S.Left('abc')) | ||
//. Right([1, 2, 3]) | ||
//. ``` | ||
//# Either#equals :: Either a b ~> Either a b -> Boolean | ||
//. | ||
//. Takes an Either and returns `true` if: | ||
//. | ||
//. - it is a Left and `this` is a Left, and their values are equal, | ||
//. in [SameValue][] terms; or | ||
//. | ||
//. - it is a Right and `this` is a Right, and their values are equal, | ||
//. in [SameValue][] terms. | ||
//. | ||
//. ```javascript | ||
//. > S.Right(42).equals(S.Right(42)) | ||
//. true | ||
//. | ||
//. > S.Right(42).equals(S.Left(42)) | ||
//. false | ||
//. ``` | ||
//# Either#map :: Either a b ~> (b -> c) -> Either a c | ||
//. | ||
//. Takes a function and returns `this` if `this` is a Left; otherwise it | ||
//. returns a Right whose value is the result of applying the function to | ||
//. this Right's value. | ||
//. | ||
//. ```javascript | ||
//. > S.Left('Cannot divide by zero').map(R.inc) | ||
//. Left("Cannot divide by zero") | ||
//. | ||
//. > S.Right(42).map(R.inc) | ||
//. Right(43) | ||
//. ``` | ||
//# Either#of :: Either a b ~> b -> Either a b | ||
//. | ||
//. Takes a value of any type and returns a Right with the given value. | ||
//. | ||
//. ```javascript | ||
//. > S.Left('Cannot divide by zero').of(42) | ||
//. Right(42) | ||
//. ``` | ||
Either.prototype.of = Either.of; | ||
//# Either#toBoolean :: Either a b ~> Boolean | ||
//. | ||
//. Returns `false` if `this` is a Left; `true` if `this` is a Right. | ||
//. | ||
//. ```javascript | ||
//. > S.Left(42).toBoolean() | ||
//. false | ||
//. | ||
//. > S.Right(42).toBoolean() | ||
//. true | ||
//. ``` | ||
//# Either#toString :: Either a b ~> String | ||
//. | ||
//. Returns the string representation of the Either. | ||
//. | ||
//. ```javascript | ||
//. > S.Left('Cannot divide by zero').toString() | ||
//. "Left(\\"Cannot divide by zero\\")" | ||
//. | ||
//. > S.Right([1, 2, 3]).toString() | ||
//. "Right([1, 2, 3])" | ||
//. ``` | ||
//# Either#type :: Type | ||
//. | ||
//. A reference to the Either type. Useful for determining whether two | ||
//. values such as `S.Left('Cannot divide by zero')` and `S.Right(42)` | ||
//. are of the same type. | ||
Either.prototype.type = Either; | ||
function Left(value) { | ||
//# Left :: a -> Either a b | ||
//. | ||
//. Takes a value of any type and returns a Left with the given value. | ||
//. Though this is a constructor function the `new` keyword needn't be | ||
//. used. | ||
//. | ||
//. ```javascript | ||
//. > S.Left('Cannot divide by zero') | ||
//. Left("Cannot divide by zero") | ||
//. ``` | ||
var Left = S.Left = function Left(value) { | ||
if (!(this instanceof Left)) { | ||
@@ -176,16 +673,51 @@ return new Left(value); | ||
this.value = value; | ||
} | ||
}; | ||
extend(Left, Either); | ||
// Left#equals :: Either a b -> Boolean | ||
// Left#ap :: Either a (b -> c) ~> Either a b -> Either a c | ||
Left.prototype.ap = function(x) { | ||
return this; | ||
}; | ||
// Left#chain :: Either a b ~> (b -> Either a c) -> Either a c | ||
Left.prototype.chain = function(f) { | ||
return this; | ||
}; | ||
// Left#concat :: Either a b ~> Either a b -> Either a b | ||
Left.prototype.concat = function(either) { | ||
return R.is(Left, either) ? Left(this.value.concat(either.value)) : either; | ||
}; | ||
// Left#equals :: Either a b ~> Either a b -> Boolean | ||
Left.prototype.equals = function(either) { | ||
return either instanceof Left && either.value === this.value; | ||
return either instanceof Left && R.eqProps('value', either, this); | ||
}; | ||
// Left#map :: (b -> c) -> Either a c | ||
Left.prototype.map = function(f) { // jshint ignore:line | ||
// Left#map :: Either a b ~> (b -> c) -> Either a c | ||
Left.prototype.map = function(f) { | ||
return this; | ||
}; | ||
function Right(value) { | ||
// Left#toBoolean :: Either a b ~> Boolean | ||
Left.prototype.toBoolean = function() { | ||
return false; | ||
}; | ||
// Left#toString :: Either a b ~> String | ||
Left.prototype.toString = function() { | ||
return 'Left(' + R.toString(this.value) + ')'; | ||
}; | ||
//# Right :: b -> Either a b | ||
//. | ||
//. Takes a value of any type and returns a Right with the given value. | ||
//. Though this is a constructor function the `new` keyword needn't be | ||
//. used. | ||
//. | ||
//. ```javascript | ||
//. > S.Right(42) | ||
//. Right(42) | ||
//. ``` | ||
var Right = S.Right = function Right(value) { | ||
if (!(this instanceof Right)) { | ||
@@ -195,11 +727,26 @@ return new Right(value); | ||
this.value = value; | ||
} | ||
}; | ||
extend(Right, Either); | ||
// Right#equals :: Either a b -> Boolean | ||
// Right#ap :: Either a (b -> c) ~> Either a b -> Either a c | ||
Right.prototype.ap = function(x) { | ||
return x.map(this.value); | ||
}; | ||
// Right#chain :: Either a b ~> (b -> Either a c) -> Either a c | ||
Right.prototype.chain = function(f) { | ||
return f(this.value); | ||
}; | ||
// Right#concat :: Either a b ~> Either a b -> Either a b | ||
Right.prototype.concat = function(either) { | ||
return R.is(Right, either) ? Right(this.value.concat(either.value)) : this; | ||
}; | ||
// Right#equals :: Either a b ~> Either a b -> Boolean | ||
Right.prototype.equals = function(either) { | ||
return either instanceof Right && either.value === this.value; | ||
return either instanceof Right && R.eqProps('value', either, this); | ||
}; | ||
// Right#map :: (b -> c) -> Either a c | ||
// Right#map :: Either a b ~> (b -> c) -> Either a c | ||
Right.prototype.map = function(f) { | ||
@@ -209,4 +756,27 @@ return new Right(f(this.value)); | ||
// either :: (a -> c) -> (b -> c) -> Either a b -> c | ||
var either = curry(function(l, r, either) { | ||
// Right#toBoolean :: Either a b ~> Boolean | ||
Right.prototype.toBoolean = function() { | ||
return true; | ||
}; | ||
// Right#toString :: Either a b ~> String | ||
Right.prototype.toString = function() { | ||
return 'Right(' + R.toString(this.value) + ')'; | ||
}; | ||
//# either :: (a -> c) -> (b -> c) -> Either a b -> c | ||
//. | ||
//. Takes two functions and an Either, and returns the result of | ||
//. applying the first function to the Left's value, if the Either | ||
//. is a Left, or the result of applying the second function to the | ||
//. Right's value, if the Either is a Right. | ||
//. | ||
//. ```javascript | ||
//. > S.either(R.toUpper, R.toString, S.Left('Cannot divide by zero')) | ||
//. "CANNOT DIVIDE BY ZERO" | ||
//. | ||
//. > S.either(R.toUpper, R.toString, S.Right(42)) | ||
//. "42" | ||
//. ``` | ||
S.either = R.curry(function(l, r, either) { | ||
switch (true) { | ||
@@ -222,21 +792,108 @@ case either instanceof Left: | ||
// control /////////////////////////////////////////////////////////////// | ||
//. ### Control | ||
// or :: f a -> f a -> f a | ||
var or = curry(function(x, y) { | ||
if (toString_.call(x) !== toString_.call(y) || x.type !== y.type) { | ||
var assertTypeMatch = function(x, y) { | ||
if (R.type(x) !== R.type(y) || x.type !== y.type) { | ||
throw new TypeError('Type mismatch'); | ||
} else if (typeof x.or === 'function') { | ||
return x.or(y); | ||
} else if (isArray(x)) { | ||
return x.length > 0 ? x : y; | ||
} else { | ||
throw new TypeError('"or" unspecified for ' + x.constructor.name); | ||
} | ||
}; | ||
// toBoolean :: * -> Boolean | ||
var toBoolean = function(x) { | ||
if (R.is(Array, x)) return x.length > 0; | ||
if (R.is(Boolean, x)) return x; | ||
if (R.is(Function, x.toBoolean)) return x.toBoolean(); | ||
throw new TypeError(R.toString(x) + ' does not have a "toBoolean" method'); | ||
}; | ||
// empty :: a -> a | ||
var empty = function(x) { | ||
if (R.is(Array, x)) return []; | ||
if (R.is(Boolean, x)) return false; | ||
if (R.is(Function, x.empty)) return x.empty(); | ||
throw new TypeError(R.toString(x) + ' does not have an "empty" method'); | ||
}; | ||
//# and :: a -> a -> a | ||
//. | ||
//. Takes two values of the same type and returns the second value | ||
//. if the first is "true"; the first value otherwise. An array is | ||
//. considered "true" if its length is greater than zero. The Boolean | ||
//. value `true` is also considered "true". Other types must provide | ||
//. a `toBoolean` method. | ||
//. | ||
//. ```javascript | ||
//. > S.and(S.Just(1), S.Just(2)) | ||
//. Just(2) | ||
//. | ||
//. > S.and(S.Nothing(), S.Just(3)) | ||
//. Nothing() | ||
//. ``` | ||
S.and = R.curry(function(x, y) { | ||
assertTypeMatch(x, y); | ||
return toBoolean(x) ? y : x; | ||
}); | ||
// list ////////////////////////////////////////////////////////////////// | ||
//# or :: a -> a -> a | ||
//. | ||
//. Takes two values of the same type and returns the first value if it | ||
//. is "true"; the second value otherwise. An array is considered "true" | ||
//. if its length is greater than zero. The Boolean value `true` is also | ||
//. considered "true". Other types must provide a `toBoolean` method. | ||
//. | ||
//. ```javascript | ||
//. > S.or(S.Just(1), S.Just(2)) | ||
//. Just(1) | ||
//. | ||
//. > S.or(S.Nothing(), S.Just(3)) | ||
//. Just(3) | ||
//. ``` | ||
var or = S.or = R.curry(function(x, y) { | ||
assertTypeMatch(x, y); | ||
return toBoolean(x) ? x : y; | ||
}); | ||
// at :: Number -> [a] -> Maybe a | ||
var at = curry(function(n, xs) { | ||
//# xor :: a -> a -> a | ||
//. | ||
//. Takes two values of the same type and returns the "true" value | ||
//. if one value is "true" and the other is "false"; otherwise it | ||
//. returns the type's "false" value. An array is considered "true" | ||
//. if its length is greater than zero. The Boolean value `true` is | ||
//. also considered "true". Other types must provide `toBoolean` and | ||
//. `empty` methods. | ||
//. | ||
//. ```javascript | ||
//. > S.xor(S.Nothing(), S.Just(1)) | ||
//. Just(1) | ||
//. | ||
//. > S.xor(S.Just(2), S.Just(3)) | ||
//. Nothing() | ||
//. ``` | ||
S.xor = R.curry(function(x, y) { | ||
assertTypeMatch(x, y); | ||
var xBool = toBoolean(x); | ||
var yBool = toBoolean(y); | ||
var xEmpty = empty(x); | ||
return xBool !== yBool ? or(x, y) : xEmpty; | ||
}); | ||
//. ### List | ||
//# at :: Number -> [a] -> Maybe a | ||
//. | ||
//. Takes an index and a list and returns Just the element of the list at | ||
//. the index if the index is within the list's bounds; Nothing otherwise. | ||
//. A negative index represents an offset from the length of the list. | ||
//. | ||
//. ```javascript | ||
//. > S.at(2, ['a', 'b', 'c', 'd', 'e']) | ||
//. Just("c") | ||
//. | ||
//. > S.at(5, ['a', 'b', 'c', 'd', 'e']) | ||
//. Nothing() | ||
//. | ||
//. > S.at(-2, ['a', 'b', 'c', 'd', 'e']) | ||
//. Just("d") | ||
//. ``` | ||
var at = S.at = R.curry(function(n, xs) { | ||
var len = xs.length; | ||
@@ -247,20 +904,74 @@ var idx = n < 0 ? len + n : n; | ||
// head :: [a] -> Maybe a | ||
var head = at(0); | ||
//# head :: [a] -> Maybe a | ||
//. | ||
//. Takes a list and returns Just the first element of the list if the | ||
//. list contains at least one element; Nothing if the list is empty. | ||
//. | ||
//. ```javascript | ||
//. > S.head([1, 2, 3]) | ||
//. Just(1) | ||
//. | ||
//. > S.head([]) | ||
//. Nothing() | ||
//. ``` | ||
S.head = at(0); | ||
// last :: [a] -> Maybe a | ||
var last = at(-1); | ||
//# last :: [a] -> Maybe a | ||
//. | ||
//. Takes a list and returns Just the last element of the list if the | ||
//. list contains at least one element; Nothing if the list is empty. | ||
//. | ||
//. ```javascript | ||
//. > S.last([1, 2, 3]) | ||
//. Just(3) | ||
//. | ||
//. > S.last([]) | ||
//. Nothing() | ||
//. ``` | ||
S.last = at(-1); | ||
// tail :: [a] -> Maybe [a] | ||
var tail = function(xs) { | ||
return xs.length > 0 ? Just(slice_.call(xs, 1)) : Nothing(); | ||
}; | ||
//# tail :: [a] -> Maybe [a] | ||
//. | ||
//. Takes a list and returns Just a list containing all but the first | ||
//. of the list's elements if the list contains at least one element; | ||
//. Nothing if the list is empty. | ||
//. | ||
//. ```javascript | ||
//. > S.tail([1, 2, 3]) | ||
//. Just([2, 3]) | ||
//. | ||
//. > S.tail([]) | ||
//. Nothing() | ||
//. ``` | ||
S.tail = R.ifElse(R.isEmpty, Nothing, R.compose(Just, R.tail)); | ||
// init :: [a] -> Maybe [a] | ||
var init = function(xs) { | ||
return xs.length > 0 ? Just(slice_.call(xs, 0, -1)) : Nothing(); | ||
}; | ||
//# init :: [a] -> Maybe [a] | ||
//. | ||
//. Takes a list and returns Just a list containing all but the last | ||
//. of the list's elements if the list contains at least one element; | ||
//. Nothing if the list is empty. | ||
//. | ||
//. ```javascript | ||
//. > S.init([1, 2, 3]) | ||
//. Just([1, 2]) | ||
//. | ||
//. > S.init([]) | ||
//. Nothing() | ||
//. ``` | ||
S.init = R.ifElse(R.isEmpty, Nothing, R.compose(Just, R.init)); | ||
// find :: (a -> Boolean) -> [a] -> Maybe a | ||
var find = curry(function(pred, xs) { | ||
//# find :: (a -> Boolean) -> [a] -> Maybe a | ||
//. | ||
//. Takes a predicate and a list and returns Just the leftmost element of | ||
//. the list which satisfies the predicate; Nothing if none of the list's | ||
//. elements satisfies the predicate. | ||
//. | ||
//. ```javascript | ||
//. > S.find(function(n) { return n < 0; }, [1, -2, 3, -4, 5]) | ||
//. Just(-2) | ||
//. | ||
//. > S.find(function(n) { return n < 0; }, [1, 2, 3, 4, 5]) | ||
//. Nothing() | ||
//. ``` | ||
S.find = R.curry(function(pred, xs) { | ||
for (var idx = 0, len = xs.length; idx < len; idx += 1) { | ||
@@ -274,25 +985,140 @@ if (pred(xs[idx])) { | ||
// object //////////////////////////////////////////////////////////////// | ||
var sanctifyIndexOf = function(f) { | ||
return R.curry(R.compose(R.ifElse(R.gte(_, 0), Just, Nothing), f)); | ||
}; | ||
// get :: String -> Object -> Maybe * | ||
var get = curry(function(key, obj) { | ||
return hasOwnProperty_.call(obj, key) ? Just(obj[key]) : Nothing(); | ||
//# indexOf :: a -> [a] -> Maybe Number | ||
//. | ||
//. Takes a value of any type and a list, and returns Just the index | ||
//. of the first occurrence of the value in the list, if applicable; | ||
//. Nothing otherwise. | ||
//. | ||
//. ```javascript | ||
//. > S.indexOf('a', ['b', 'a', 'n', 'a', 'n', 'a']) | ||
//. Just(1) | ||
//. | ||
//. > S.indexOf('x', ['b', 'a', 'n', 'a', 'n', 'a']) | ||
//. Nothing() | ||
//. ``` | ||
S.indexOf = sanctifyIndexOf(R.indexOf); | ||
//# lastIndexOf :: a -> [a] -> Maybe Number | ||
//. | ||
//. Takes a value of any type and a list, and returns Just the index | ||
//. of the last occurrence of the value in the list, if applicable; | ||
//. Nothing otherwise. | ||
//. | ||
//. ```javascript | ||
//. > S.lastIndexOf('a', ['b', 'a', 'n', 'a', 'n', 'a']) | ||
//. Just(5) | ||
//. | ||
//. > S.lastIndexOf('x', ['b', 'a', 'n', 'a', 'n', 'a']) | ||
//. Nothing() | ||
//. ``` | ||
S.lastIndexOf = sanctifyIndexOf(R.lastIndexOf); | ||
//# pluck :: String -> [{String: *}] -> [Maybe *] | ||
//. | ||
//. Takes a list of objects and plucks the value of the specified key | ||
//. for each object in the list. Returns the value wrapped in a Just | ||
//. if an object has the key and a Nothing if it does not. | ||
//. | ||
//. ```javascript | ||
//. > S.pluck('a', [{a: 1, b: 2}, {a: 4, b: 5}, {b: 3, c: 7}]) | ||
//. [Just(1), Just(4), Nothing()] | ||
//. | ||
//. > S.pluck('x', [{x: 1}, {x: 2}, {x: undefined}]) | ||
//. [Just(1), Just(2), Just(undefined)] | ||
//. ``` | ||
S.pluck = R.curry(function(key, xs) { | ||
return R.map(get(key), xs); | ||
}); | ||
// parse ///////////////////////////////////////////////////////////////// | ||
//. ### Object | ||
// parseDate :: String -> Maybe Date | ||
var parseDate = function(s) { | ||
//# get :: String -> Object -> Maybe * | ||
//. | ||
//. Takes a property name and an object and returns Just the value of | ||
//. the specified property of the object if the object has such an own | ||
//. property; Nothing otherwise. | ||
//. | ||
//. ```javascript | ||
//. > S.get('x', {x: 1, y: 2}) | ||
//. Just(1) | ||
//. | ||
//. > S.get('toString', {x: 1, y: 2}) | ||
//. Nothing() | ||
//. ``` | ||
var get = S.get = R.ifElse(R.has, R.compose(Just, R.prop), Nothing); | ||
//# gets :: [String] -> Object -> Maybe * | ||
//. | ||
//. Takes a list of property names and an object and returns Just the | ||
//. value at the path specified by the list of property names if such | ||
//. a path exists; Nothing otherwise. | ||
//. | ||
//. ```javascript | ||
//. > S.gets(['a', 'b', 'c'], {a: {b: {c: 42}}}) | ||
//. Just(42) | ||
//. | ||
//. > S.gets(['a', 'b', 'c'], {}) | ||
//. Nothing() | ||
//. ``` | ||
S.gets = R.curry(function(keys, obj) { | ||
return R.reduce(function(acc, key) { | ||
return R.chain(get(key), acc); | ||
}, Just(obj), keys); | ||
}); | ||
//. ### Parse | ||
//# parseDate :: String -> Maybe Date | ||
//. | ||
//. Takes a string and returns Just the date represented by the string | ||
//. if it does in fact represent a date; Nothing otherwise. | ||
//. | ||
//. ```javascript | ||
//. > S.parseDate('2011-01-19T17:40:00Z') | ||
//. Just(new Date("2011-01-19T17:40:00.000Z")) | ||
//. | ||
//. > S.parseDate('today') | ||
//. Nothing() | ||
//. ``` | ||
S.parseDate = R.curry(function(s) { | ||
var d = new Date(s); | ||
return d.valueOf() === d.valueOf() ? Just(d) : Nothing(); | ||
}; | ||
}); | ||
// parseFloat_ :: String -> Maybe Number | ||
var parseFloat_ = function(s) { | ||
//# parseFloat :: String -> Maybe Number | ||
//. | ||
//. Takes a string and returns Just the number represented by the string | ||
//. if it does in fact represent a number; Nothing otherwise. | ||
//. | ||
//. ```javascript | ||
//. > S.parseFloat('-123.45') | ||
//. Just(-123.45) | ||
//. | ||
//. > S.parseFloat('foo.bar') | ||
//. Nothing() | ||
//. ``` | ||
S.parseFloat = R.curry(function(s) { | ||
var n = parseFloat(s); | ||
return n === n ? Just(n) : Nothing(); | ||
}; | ||
}); | ||
// parseInt_ :: Number -> String -> Maybe Number | ||
var parseInt_ = curry(function(radix, s) { | ||
//# parseInt :: Number -> String -> Maybe Number | ||
//. | ||
//. Takes a radix (an integer between 2 and 36 inclusive) and a string, | ||
//. and returns Just the number represented by the string if it does in | ||
//. fact represent a number in the base specified by the radix; Nothing | ||
//. otherwise. | ||
//. | ||
//. ```javascript | ||
//. > S.parseInt(16, '0xFF') | ||
//. Just(255) | ||
//. | ||
//. > S.parseInt(16, '0xGG') | ||
//. Nothing() | ||
//. ``` | ||
S.parseInt = R.curry(function(radix, s) { | ||
var n = parseInt(s, radix); | ||
@@ -302,43 +1128,44 @@ return n === n ? Just(n) : Nothing(); | ||
// parseJson :: String -> Maybe * | ||
var parseJson = encase(JSON.parse); | ||
//# parseJson :: String -> Maybe * | ||
//. | ||
//. Takes a string which may or may not be valid JSON, and returns Just | ||
//. the result of applying `JSON.parse` to the string if valid; Nothing | ||
//. otherwise. | ||
//. | ||
//. ```javascript | ||
//. > S.parseJson('["foo","bar","baz"]') | ||
//. Just(["foo", "bar", "baz"]) | ||
//. | ||
//. > S.parseJson('[') | ||
//. Nothing() | ||
//. ``` | ||
S.parseJson = encase(function(s) { | ||
return JSON.parse(s); | ||
}); | ||
// exports /////////////////////////////////////////////////////////////// | ||
//. ### RegExp | ||
var sanctuary = { | ||
Either: Either, | ||
Just: Just, | ||
Left: Left, | ||
Maybe: Maybe, | ||
Nothing: Nothing, | ||
Right: Right, | ||
at: at, | ||
either: either, | ||
encase: encase, | ||
find: find, | ||
get: get, | ||
head: head, | ||
init: init, | ||
fromMaybe: fromMaybe, | ||
last: last, | ||
or: or, | ||
parseDate: parseDate, | ||
parseFloat: parseFloat_, | ||
parseInt: parseInt_, | ||
parseJson: parseJson, | ||
tail: tail, | ||
toMaybe: toMaybe, | ||
}; | ||
//# match :: RegExp -> String -> Maybe [Maybe String] | ||
//. | ||
//. Takes a pattern and a string, and returns Just a list of matches | ||
//. if the pattern matches the string; Nothing otherwise. Each match | ||
//. has type `Maybe String`, where a Nothing represents an unmatched | ||
//. optional capturing group. | ||
//. | ||
//. ```javascript | ||
//. > S.match(/(good)?bye/, 'goodbye') | ||
//. Just([Just("goodbye"), Just("good")]) | ||
//. | ||
//. > S.match(/(good)?bye/, 'bye') | ||
//. Just([Just("bye"), Nothing()]) | ||
//. ``` | ||
S.match = R.curry(R.compose(R.map(R.map(S.toMaybe)), S.toMaybe, R.match)); | ||
/* global define, window */ | ||
}.call(this)); | ||
/* istanbul ignore else */ | ||
if (typeof module !== 'undefined') { | ||
module.exports = sanctuary; | ||
} else if (typeof define === 'function' && define.amd) { | ||
define(sanctuary); | ||
} else { | ||
window.sanctuary = sanctuary; | ||
} | ||
}()); | ||
//. [Monad]: https://github.com/fantasyland/fantasy-land#monad | ||
//. [Monoid]: https://github.com/fantasyland/fantasy-land#monoid | ||
//. [R.map]: http://ramdajs.com/docs/#map | ||
//. [Ramda]: http://ramdajs.com/ | ||
//. [SameValue]: http://ecma-international.org/ecma-262/5.1/#sec-9.12 | ||
//. [Semigroup]: https://github.com/fantasyland/fantasy-land#semigroup |
{ | ||
"name": "sanctuary", | ||
"version": "0.4.0", | ||
"version": "0.5.0", | ||
"description": "Refuge from unsafe JavaScript", | ||
@@ -10,3 +10,5 @@ "license": "MIT", | ||
}, | ||
"dependencies": {}, | ||
"dependencies": { | ||
"ramda": "0.14.x" | ||
}, | ||
"devDependencies": { | ||
@@ -17,2 +19,3 @@ "istanbul": "0.3.x", | ||
"mocha": "2.x.x", | ||
"transcribe": "0.3.x", | ||
"xyz": "0.5.x" | ||
@@ -19,0 +22,0 @@ }, |
795
README.md
# Sanctuary | ||
Sanctuary is small functional programming library inspired by Haskell and | ||
PureScript. Sanctuary makes it possible to write safe code without null checks. | ||
Sanctuary is a small functional programming library inspired by Haskell | ||
and PureScript. It depends on and works nicely with [Ramda][]. Sanctuary | ||
makes it possible to write safe code without null checks. | ||
In JavaScript it's trivial to introduce a possible run-time type error: | ||
words[0].toUpperCase() | ||
If `words` is `[]` we'll get a familiar error at run-time: | ||
TypeError: Cannot read property 'toUpperCase' of undefined | ||
Sanctuary gives us a fighting chance of avoiding such errors. We might | ||
write: | ||
R.map(R.toUpper, S.head(words)) | ||
## Types | ||
Sanctuary uses Haskell-like type signatures to describe the types of | ||
values, including functions. `'foo'`, for example, has type `String`; | ||
`[1, 2, 3]` has type `[Number]`. The arrow (`->`) is used to express a | ||
function's type. `Math.abs`, for example, has type `Number -> Number`. | ||
That is, it takes an argument of type `Number` and returns a value of | ||
type `Number`. | ||
[`R.map`][R.map] has type `(a -> b) -> [a] -> [b]`. That is, it takes | ||
an argument of type `a -> b` and returns a value of type `[a] -> [b]`. | ||
`a` and `b` are type variables: applying `R.map` to a value of type | ||
`String -> Number` will give a value of type `[String] -> [Number]`. | ||
Sanctuary embraces types. JavaScript doesn't support algebraic data types, | ||
but these can be simulated by providing a group of constructor functions | ||
whose prototypes provide the same set of methods. A value of the Maybe | ||
type, for example, is created via the Nothing constructor or the Just | ||
constructor. | ||
It's necessary to extend Haskell's notation to describe implicit arguments | ||
to the *methods* provided by Sanctuary's types. In `x.map(y)`, for example, | ||
the `map` method takes an implicit argument `x` in addition to the explicit | ||
argument `y`. The type of the value upon which a method is invoked appears | ||
at the beginning of the signature, separated from the arguments and return | ||
value by a squiggly arrow (`~>`). The type of the `map` method of the Maybe | ||
type is written `Maybe a ~> (a -> b) -> Maybe b`. One could read this as: | ||
_When the `map` method is invoked on a value of type `Maybe a` | ||
(for any type `a`) with an argument of type `a -> b` (for any type `b`), | ||
it returns a value of type `Maybe b`._ | ||
## API | ||
### Combinator | ||
<h4 name="K"><code><a href="https://github.com/plaid/sanctuary/blob/v0.5.0/index.js#L99">K :: a -> b -> a</a></code></h4> | ||
The K combinator. Takes two values and returns the first. Equivalent to | ||
Haskell's `const` function. | ||
```javascript | ||
words[0].toUpperCase() | ||
> S.K('foo', 'bar') | ||
"foo" | ||
> R.map(S.K(42), R.range(0, 5)) | ||
[42, 42, 42, 42, 42] | ||
``` | ||
If `words` is `['foo', 'bar', 'baz']` this expression will evaluate to `'FOO'`. | ||
But what if `words` is `[]`? | ||
### Maybe type | ||
Sanctuary is stricter in its types than most JavaScript libraries. Its `head` | ||
function, for example, has type `a -> Maybe a` which means it never returns | ||
null or undefined. This forces one to consider the empty case. | ||
<h4 name="Maybe"><code><a href="https://github.com/plaid/sanctuary/blob/v0.5.0/index.js#L116">Maybe :: Type</a></code></h4> | ||
`S.head(words)` evaluates to a value of type `Maybe String`. One may derive | ||
from it a value of type `String` by applying `S.fromMaybe`. The `toUpperCase` | ||
method can then be invoked safely: | ||
The Maybe type represents optional values: a value of type `Maybe a` is | ||
either a Just whose value is of type `a` or a Nothing (with no value). | ||
The Maybe type satisfies the [Monoid][] and [Monad][] specifications. | ||
<h4 name="Maybe.empty"><code><a href="https://github.com/plaid/sanctuary/blob/v0.5.0/index.js#L126">Maybe.empty :: -> Maybe a</a></code></h4> | ||
Returns a Nothing. | ||
```javascript | ||
// :: String | ||
S.fromMaybe('', S.head(words)).toUpperCase() | ||
> S.Maybe.empty() | ||
Nothing() | ||
``` | ||
Without Sanctuary, one might have written: | ||
<h4 name="Maybe.of"><code><a href="https://github.com/plaid/sanctuary/blob/v0.5.0/index.js#L138">Maybe.of :: a -> Maybe a</a></code></h4> | ||
Takes a value of any type and returns a Just with the given value. | ||
```javascript | ||
// :: String | ||
(words.length > 0 ? words[0] : '').toUpperCase() | ||
> S.Maybe.of(42) | ||
Just(42) | ||
``` | ||
Maybe is a functor, so one can use its `map` method to produce another Maybe: | ||
<h4 name="Maybe.prototype.ap"><code><a href="https://github.com/plaid/sanctuary/blob/v0.5.0/index.js#L150">Maybe#ap :: Maybe (a -> b) ~> Maybe a -> Maybe b</a></code></h4> | ||
Takes a value of type `Maybe a` and returns a Nothing unless `this` | ||
is a Just *and* the argument is a Just, in which case it returns a | ||
Just whose value is the result of of applying this Just's value to | ||
the given Just's value. | ||
```javascript | ||
// :: Maybe String | ||
S.head(words).map(function(word) { return word.toUpperCase(); }) | ||
> S.Nothing().ap(S.Just(42)) | ||
Nothing() | ||
> S.Just(R.inc).ap(S.Nothing()) | ||
Nothing() | ||
> S.Just(R.inc).ap(S.Just(42)) | ||
Just(43) | ||
``` | ||
This approach is even cleaner if one uses [Ramda][1]: | ||
<h4 name="Maybe.prototype.chain"><code><a href="https://github.com/plaid/sanctuary/blob/v0.5.0/index.js#L168">Maybe#chain :: Maybe a ~> (a -> Maybe b) -> Maybe b</a></code></h4> | ||
Takes a function and returns `this` if `this` is a Nothing; otherwise | ||
it returns the result of applying the function to this Just's value. | ||
```javascript | ||
// :: Maybe String | ||
R.map(R.toUpper, S.head(words)) | ||
> S.Nothing().chain(S.parseFloat) | ||
Nothing() | ||
> S.Just('xxx').chain(S.parseFloat) | ||
Nothing() | ||
> S.Just('12.34').chain(S.parseFloat) | ||
Just(12.34) | ||
``` | ||
<h4 name="Maybe.prototype.concat"><code><a href="https://github.com/plaid/sanctuary/blob/v0.5.0/index.js#L184">Maybe#concat :: Maybe a ~> Maybe a -> Maybe a</a></code></h4> | ||
[1]: http://ramdajs.com/ | ||
Returns the result of concatenating two Maybe values of the same type. | ||
`a` must have a [Semigroup][] (indicated by the presence of a `concat` | ||
method). | ||
If `this` is a Nothing and the argument is a Nothing, this method returns | ||
a Nothing. | ||
If `this` is a Just and the argument is a Just, this method returns a | ||
Just whose value is the result of concatenating this Just's value and | ||
the given Just's value. | ||
Otherwise, this method returns the Just. | ||
```javascript | ||
> S.Nothing().concat(S.Nothing()) | ||
Nothing() | ||
> S.Just([1, 2, 3]).concat(S.Just([4, 5, 6])) | ||
Just([1, 2, 3, 4, 5, 6]) | ||
> S.Nothing().concat(S.Just([1, 2, 3])) | ||
Just([1, 2, 3]) | ||
> S.Just([1, 2, 3]).concat(S.Nothing()) | ||
Just([1, 2, 3]) | ||
``` | ||
<h4 name="Maybe.prototype.empty"><code><a href="https://github.com/plaid/sanctuary/blob/v0.5.0/index.js#L213">Maybe#empty :: Maybe a ~> Maybe a</a></code></h4> | ||
Returns a Nothing. | ||
```javascript | ||
> S.Just(42).empty() | ||
Nothing() | ||
``` | ||
<h4 name="Maybe.prototype.equals"><code><a href="https://github.com/plaid/sanctuary/blob/v0.5.0/index.js#L223">Maybe#equals :: Maybe a ~> Maybe a -> Boolean</a></code></h4> | ||
Takes a Maybe and returns `true` if: | ||
- it is a Nothing and `this` is a Nothing; or | ||
- it is a Just and `this` is a Just, and their values are equal, | ||
in [SameValue][] terms. | ||
```javascript | ||
> S.Nothing().equals(S.Nothing()) | ||
true | ||
> S.Just(42).equals(S.Just(42)) | ||
true | ||
> S.Just(42).equals(S.Just(43)) | ||
false | ||
> S.Just(42).equals(S.Nothing()) | ||
false | ||
``` | ||
<h4 name="Maybe.prototype.filter"><code><a href="https://github.com/plaid/sanctuary/blob/v0.5.0/index.js#L246">Maybe#filter :: Maybe a ~> (a -> Boolean) -> Maybe a</a></code></h4> | ||
Takes a predicate and returns `this` if `this` is a Just whose value | ||
satisfies the predicate; Nothing otherwise. | ||
```javascript | ||
> S.Just(42).filter(function(n) { return n % 2 === 0; }) | ||
Just(42) | ||
> S.Just(43).filter(function(n) { return n % 2 === 0; }) | ||
Nothing() | ||
``` | ||
<h4 name="Maybe.prototype.map"><code><a href="https://github.com/plaid/sanctuary/blob/v0.5.0/index.js#L262">Maybe#map :: Maybe a ~> (a -> b) -> Maybe b</a></code></h4> | ||
Takes a function and returns `this` if `this` is a Nothing; otherwise | ||
it returns a Just whose value is the result of applying the function to | ||
this Just's value. | ||
```javascript | ||
> S.Nothing().map(R.inc) | ||
Nothing() | ||
> S.Just(42).map(R.inc) | ||
Just(43) | ||
``` | ||
<h4 name="Maybe.prototype.of"><code><a href="https://github.com/plaid/sanctuary/blob/v0.5.0/index.js#L276">Maybe#of :: Maybe a ~> b -> Maybe b</a></code></h4> | ||
Takes a value of any type and returns a Just with the given value. | ||
```javascript | ||
> S.Nothing().of(42) | ||
Just(42) | ||
``` | ||
<h4 name="Maybe.prototype.toBoolean"><code><a href="https://github.com/plaid/sanctuary/blob/v0.5.0/index.js#L286">Maybe#toBoolean :: Maybe a ~> Boolean</a></code></h4> | ||
Returns `false` if `this` is a Nothing; `true` if `this` is a Just. | ||
```javascript | ||
> S.Nothing().toBoolean() | ||
false | ||
> S.Just(42).toBoolean() | ||
true | ||
``` | ||
<h4 name="Maybe.prototype.toString"><code><a href="https://github.com/plaid/sanctuary/blob/v0.5.0/index.js#L298">Maybe#toString :: Maybe a ~> String</a></code></h4> | ||
Returns the string representation of the Maybe. | ||
```javascript | ||
> S.Nothing().toString() | ||
"Nothing()" | ||
> S.Just([1, 2, 3]).toString() | ||
"Just([1, 2, 3])" | ||
``` | ||
<h4 name="Maybe.prototype.type"><code><a href="https://github.com/plaid/sanctuary/blob/v0.5.0/index.js#L310">Maybe#type :: Type</a></code></h4> | ||
A reference to the Maybe type. Useful for determining whether two | ||
values such as `S.Nothing()` and `S.Just(42)` are of the same type. | ||
<h4 name="Nothing"><code><a href="https://github.com/plaid/sanctuary/blob/v0.5.0/index.js#L316">Nothing :: -> Maybe a</a></code></h4> | ||
Returns a Nothing. Though this is a constructor function the `new` | ||
keyword needn't be used. | ||
```javascript | ||
> S.Nothing() | ||
Nothing() | ||
``` | ||
<h4 name="Just"><code><a href="https://github.com/plaid/sanctuary/blob/v0.5.0/index.js#L367">Just :: a -> Maybe a</a></code></h4> | ||
Takes a value of any type and returns a Just with the given value. | ||
Though this is a constructor function the `new` keyword needn't be | ||
used. | ||
```javascript | ||
> S.Just(42) | ||
Just(42) | ||
``` | ||
<h4 name="fromMaybe"><code><a href="https://github.com/plaid/sanctuary/blob/v0.5.0/index.js#L421">fromMaybe :: a -> Maybe a -> a</a></code></h4> | ||
Takes a default value and a Maybe, and returns the Maybe's value | ||
if the Maybe is a Just; the default value otherwise. | ||
```javascript | ||
> S.fromMaybe(0, S.Just(42)) | ||
42 | ||
> S.fromMaybe(0, S.Nothing()) | ||
0 | ||
``` | ||
<h4 name="toMaybe"><code><a href="https://github.com/plaid/sanctuary/blob/v0.5.0/index.js#L444">toMaybe :: a? -> Maybe a</a></code></h4> | ||
Takes a value and returns Nothing if the value is null or undefined; | ||
Just the value otherwise. | ||
```javascript | ||
> S.toMaybe(null) | ||
Nothing() | ||
> S.toMaybe(42) | ||
Just(42) | ||
``` | ||
<h4 name="encase"><code><a href="https://github.com/plaid/sanctuary/blob/v0.5.0/index.js#L458">encase :: (* -> a) -> (* -> Maybe a)</a></code></h4> | ||
Takes a function `f` which may throw and returns a curried function | ||
`g` which will not throw. The result of applying `g` is determined by | ||
applying `f` to the same arguments: if this succeeds, `g` returns Just | ||
the result; otherwise `g` returns Nothing. | ||
```javascript | ||
> S.encase(eval)('1 + 1') | ||
Just(2) | ||
> S.encase(eval)('1 +') | ||
Nothing() | ||
``` | ||
### Either type | ||
<h4 name="Either"><code><a href="https://github.com/plaid/sanctuary/blob/v0.5.0/index.js#L484">Either :: Type</a></code></h4> | ||
The Either type represents values with two possibilities: a value of type | ||
`Either a b` is either a Left whose value is of type `a` or a Right whose | ||
value is of type `b`. | ||
The Either type satisfies the [Semigroup][] and [Monad][] specifications. | ||
<h4 name="Either.of"><code><a href="https://github.com/plaid/sanctuary/blob/v0.5.0/index.js#L495">Either.of :: b -> Either a b</a></code></h4> | ||
Takes a value of any type and returns a Right with the given value. | ||
```javascript | ||
> S.Either.of(42) | ||
Right(42) | ||
``` | ||
<h4 name="Either.prototype.ap"><code><a href="https://github.com/plaid/sanctuary/blob/v0.5.0/index.js#L507">Either#ap :: Either a (b -> c) ~> Either a b -> Either a c</a></code></h4> | ||
Takes a value of type `Either a b` and returns a Left unless `this` | ||
is a Right *and* the argument is a Right, in which case it returns | ||
a Right whose value is the result of applying this Right's value to | ||
the given Right's value. | ||
```javascript | ||
> S.Left('Cannot divide by zero').ap(S.Right(42)) | ||
Left("Cannot divide by zero") | ||
> S.Right(R.inc).ap(S.Left('Cannot divide by zero')) | ||
Left("Cannot divide by zero") | ||
> S.Right(R.inc).ap(S.Right(42)) | ||
Right(43) | ||
``` | ||
<h4 name="Either.prototype.chain"><code><a href="https://github.com/plaid/sanctuary/blob/v0.5.0/index.js#L525">Either#chain :: Either a b ~> (b -> Either a c) -> Either a c</a></code></h4> | ||
Takes a function and returns `this` if `this` is a Left; otherwise | ||
it returns the result of applying the function to this Right's value. | ||
```javascript | ||
> void (sqrt = function(n) { return n < 0 ? S.Left('Cannot represent square root of negative number') : S.Right(Math.sqrt(n)); }) | ||
undefined | ||
> S.Left('Cannot divide by zero').chain(sqrt) | ||
Left("Cannot divide by zero") | ||
> S.Right(-1).chain(sqrt) | ||
Left("Cannot represent square root of negative number") | ||
> S.Right(25).chain(sqrt) | ||
Right(5) | ||
``` | ||
<h4 name="Either.prototype.concat"><code><a href="https://github.com/plaid/sanctuary/blob/v0.5.0/index.js#L544">Either#concat :: Either a b ~> Either a b -> Either a b</a></code></h4> | ||
Returns the result of concatenating two Either values of the same type. | ||
`a` must have a [Semigroup][] (indicated by the presence of a `concat` | ||
method), as must `b`. | ||
If `this` is a Left and the argument is a Left, this method returns a | ||
Left whose value is the result of concatenating this Left's value and | ||
the given Left's value. | ||
If `this` is a Right and the argument is a Right, this method returns a | ||
Right whose value is the result of concatenating this Right's value and | ||
the given Right's value. | ||
Otherwise, this method returns the Right. | ||
```javascript | ||
> S.Left('abc').concat(S.Left('def')) | ||
Left("abcdef") | ||
> S.Right([1, 2, 3]).concat(S.Right([4, 5, 6])) | ||
Right([1, 2, 3, 4, 5, 6]) | ||
> S.Left('abc').concat(S.Right([1, 2, 3])) | ||
Right([1, 2, 3]) | ||
> S.Right([1, 2, 3]).concat(S.Left('abc')) | ||
Right([1, 2, 3]) | ||
``` | ||
<h4 name="Either.prototype.equals"><code><a href="https://github.com/plaid/sanctuary/blob/v0.5.0/index.js#L574">Either#equals :: Either a b ~> Either a b -> Boolean</a></code></h4> | ||
Takes an Either and returns `true` if: | ||
- it is a Left and `this` is a Left, and their values are equal, | ||
in [SameValue][] terms; or | ||
- it is a Right and `this` is a Right, and their values are equal, | ||
in [SameValue][] terms. | ||
```javascript | ||
> S.Right(42).equals(S.Right(42)) | ||
true | ||
> S.Right(42).equals(S.Left(42)) | ||
false | ||
``` | ||
<h4 name="Either.prototype.map"><code><a href="https://github.com/plaid/sanctuary/blob/v0.5.0/index.js#L592">Either#map :: Either a b ~> (b -> c) -> Either a c</a></code></h4> | ||
Takes a function and returns `this` if `this` is a Left; otherwise it | ||
returns a Right whose value is the result of applying the function to | ||
this Right's value. | ||
```javascript | ||
> S.Left('Cannot divide by zero').map(R.inc) | ||
Left("Cannot divide by zero") | ||
> S.Right(42).map(R.inc) | ||
Right(43) | ||
``` | ||
<h4 name="Either.prototype.of"><code><a href="https://github.com/plaid/sanctuary/blob/v0.5.0/index.js#L606">Either#of :: Either a b ~> b -> Either a b</a></code></h4> | ||
Takes a value of any type and returns a Right with the given value. | ||
```javascript | ||
> S.Left('Cannot divide by zero').of(42) | ||
Right(42) | ||
``` | ||
<h4 name="Either.prototype.toBoolean"><code><a href="https://github.com/plaid/sanctuary/blob/v0.5.0/index.js#L616">Either#toBoolean :: Either a b ~> Boolean</a></code></h4> | ||
Returns `false` if `this` is a Left; `true` if `this` is a Right. | ||
```javascript | ||
> S.Left(42).toBoolean() | ||
false | ||
> S.Right(42).toBoolean() | ||
true | ||
``` | ||
<h4 name="Either.prototype.toString"><code><a href="https://github.com/plaid/sanctuary/blob/v0.5.0/index.js#L628">Either#toString :: Either a b ~> String</a></code></h4> | ||
Returns the string representation of the Either. | ||
```javascript | ||
> S.Left('Cannot divide by zero').toString() | ||
"Left(\\"Cannot divide by zero\\")" | ||
> S.Right([1, 2, 3]).toString() | ||
"Right([1, 2, 3])" | ||
``` | ||
<h4 name="Either.prototype.type"><code><a href="https://github.com/plaid/sanctuary/blob/v0.5.0/index.js#L640">Either#type :: Type</a></code></h4> | ||
A reference to the Either type. Useful for determining whether two | ||
values such as `S.Left('Cannot divide by zero')` and `S.Right(42)` | ||
are of the same type. | ||
<h4 name="Left"><code><a href="https://github.com/plaid/sanctuary/blob/v0.5.0/index.js#L647">Left :: a -> Either a b</a></code></h4> | ||
Takes a value of any type and returns a Left with the given value. | ||
Though this is a constructor function the `new` keyword needn't be | ||
used. | ||
```javascript | ||
> S.Left('Cannot divide by zero') | ||
Left("Cannot divide by zero") | ||
``` | ||
<h4 name="Right"><code><a href="https://github.com/plaid/sanctuary/blob/v0.5.0/index.js#L700">Right :: b -> Either a b</a></code></h4> | ||
Takes a value of any type and returns a Right with the given value. | ||
Though this is a constructor function the `new` keyword needn't be | ||
used. | ||
```javascript | ||
> S.Right(42) | ||
Right(42) | ||
``` | ||
<h4 name="either"><code><a href="https://github.com/plaid/sanctuary/blob/v0.5.0/index.js#L753">either :: (a -> c) -> (b -> c) -> Either a b -> c</a></code></h4> | ||
Takes two functions and an Either, and returns the result of | ||
applying the first function to the Left's value, if the Either | ||
is a Left, or the result of applying the second function to the | ||
Right's value, if the Either is a Right. | ||
```javascript | ||
> S.either(R.toUpper, R.toString, S.Left('Cannot divide by zero')) | ||
"CANNOT DIVIDE BY ZERO" | ||
> S.either(R.toUpper, R.toString, S.Right(42)) | ||
"42" | ||
``` | ||
### Control | ||
<h4 name="and"><code><a href="https://github.com/plaid/sanctuary/blob/v0.5.0/index.js#L802">and :: a -> a -> a</a></code></h4> | ||
Takes two values of the same type and returns the second value | ||
if the first is "true"; the first value otherwise. An array is | ||
considered "true" if its length is greater than zero. The Boolean | ||
value `true` is also considered "true". Other types must provide | ||
a `toBoolean` method. | ||
```javascript | ||
> S.and(S.Just(1), S.Just(2)) | ||
Just(2) | ||
> S.and(S.Nothing(), S.Just(3)) | ||
Nothing() | ||
``` | ||
<h4 name="or"><code><a href="https://github.com/plaid/sanctuary/blob/v0.5.0/index.js#L822">or :: a -> a -> a</a></code></h4> | ||
Takes two values of the same type and returns the first value if it | ||
is "true"; the second value otherwise. An array is considered "true" | ||
if its length is greater than zero. The Boolean value `true` is also | ||
considered "true". Other types must provide a `toBoolean` method. | ||
```javascript | ||
> S.or(S.Just(1), S.Just(2)) | ||
Just(1) | ||
> S.or(S.Nothing(), S.Just(3)) | ||
Just(3) | ||
``` | ||
<h4 name="xor"><code><a href="https://github.com/plaid/sanctuary/blob/v0.5.0/index.js#L841">xor :: a -> a -> a</a></code></h4> | ||
Takes two values of the same type and returns the "true" value | ||
if one value is "true" and the other is "false"; otherwise it | ||
returns the type's "false" value. An array is considered "true" | ||
if its length is greater than zero. The Boolean value `true` is | ||
also considered "true". Other types must provide `toBoolean` and | ||
`empty` methods. | ||
```javascript | ||
> S.xor(S.Nothing(), S.Just(1)) | ||
Just(1) | ||
> S.xor(S.Just(2), S.Just(3)) | ||
Nothing() | ||
``` | ||
### List | ||
<h4 name="at"><code><a href="https://github.com/plaid/sanctuary/blob/v0.5.0/index.js#L867">at :: Number -> [a] -> Maybe a</a></code></h4> | ||
Takes an index and a list and returns Just the element of the list at | ||
the index if the index is within the list's bounds; Nothing otherwise. | ||
A negative index represents an offset from the length of the list. | ||
```javascript | ||
> S.at(2, ['a', 'b', 'c', 'd', 'e']) | ||
Just("c") | ||
> S.at(5, ['a', 'b', 'c', 'd', 'e']) | ||
Nothing() | ||
> S.at(-2, ['a', 'b', 'c', 'd', 'e']) | ||
Just("d") | ||
``` | ||
<h4 name="head"><code><a href="https://github.com/plaid/sanctuary/blob/v0.5.0/index.js#L889">head :: [a] -> Maybe a</a></code></h4> | ||
Takes a list and returns Just the first element of the list if the | ||
list contains at least one element; Nothing if the list is empty. | ||
```javascript | ||
> S.head([1, 2, 3]) | ||
Just(1) | ||
> S.head([]) | ||
Nothing() | ||
``` | ||
<h4 name="last"><code><a href="https://github.com/plaid/sanctuary/blob/v0.5.0/index.js#L903">last :: [a] -> Maybe a</a></code></h4> | ||
Takes a list and returns Just the last element of the list if the | ||
list contains at least one element; Nothing if the list is empty. | ||
```javascript | ||
> S.last([1, 2, 3]) | ||
Just(3) | ||
> S.last([]) | ||
Nothing() | ||
``` | ||
<h4 name="tail"><code><a href="https://github.com/plaid/sanctuary/blob/v0.5.0/index.js#L917">tail :: [a] -> Maybe [a]</a></code></h4> | ||
Takes a list and returns Just a list containing all but the first | ||
of the list's elements if the list contains at least one element; | ||
Nothing if the list is empty. | ||
```javascript | ||
> S.tail([1, 2, 3]) | ||
Just([2, 3]) | ||
> S.tail([]) | ||
Nothing() | ||
``` | ||
<h4 name="init"><code><a href="https://github.com/plaid/sanctuary/blob/v0.5.0/index.js#L932">init :: [a] -> Maybe [a]</a></code></h4> | ||
Takes a list and returns Just a list containing all but the last | ||
of the list's elements if the list contains at least one element; | ||
Nothing if the list is empty. | ||
```javascript | ||
> S.init([1, 2, 3]) | ||
Just([1, 2]) | ||
> S.init([]) | ||
Nothing() | ||
``` | ||
<h4 name="find"><code><a href="https://github.com/plaid/sanctuary/blob/v0.5.0/index.js#L947">find :: (a -> Boolean) -> [a] -> Maybe a</a></code></h4> | ||
Takes a predicate and a list and returns Just the leftmost element of | ||
the list which satisfies the predicate; Nothing if none of the list's | ||
elements satisfies the predicate. | ||
```javascript | ||
> S.find(function(n) { return n < 0; }, [1, -2, 3, -4, 5]) | ||
Just(-2) | ||
> S.find(function(n) { return n < 0; }, [1, 2, 3, 4, 5]) | ||
Nothing() | ||
``` | ||
<h4 name="indexOf"><code><a href="https://github.com/plaid/sanctuary/blob/v0.5.0/index.js#L973">indexOf :: a -> [a] -> Maybe Number</a></code></h4> | ||
Takes a value of any type and a list, and returns Just the index | ||
of the first occurrence of the value in the list, if applicable; | ||
Nothing otherwise. | ||
```javascript | ||
> S.indexOf('a', ['b', 'a', 'n', 'a', 'n', 'a']) | ||
Just(1) | ||
> S.indexOf('x', ['b', 'a', 'n', 'a', 'n', 'a']) | ||
Nothing() | ||
``` | ||
<h4 name="lastIndexOf"><code><a href="https://github.com/plaid/sanctuary/blob/v0.5.0/index.js#L988">lastIndexOf :: a -> [a] -> Maybe Number</a></code></h4> | ||
Takes a value of any type and a list, and returns Just the index | ||
of the last occurrence of the value in the list, if applicable; | ||
Nothing otherwise. | ||
```javascript | ||
> S.lastIndexOf('a', ['b', 'a', 'n', 'a', 'n', 'a']) | ||
Just(5) | ||
> S.lastIndexOf('x', ['b', 'a', 'n', 'a', 'n', 'a']) | ||
Nothing() | ||
``` | ||
<h4 name="pluck"><code><a href="https://github.com/plaid/sanctuary/blob/v0.5.0/index.js#L1003">pluck :: String -> [{String: *}] -> [Maybe *]</a></code></h4> | ||
Takes a list of objects and plucks the value of the specified key | ||
for each object in the list. Returns the value wrapped in a Just | ||
if an object has the key and a Nothing if it does not. | ||
```javascript | ||
> S.pluck('a', [{a: 1, b: 2}, {a: 4, b: 5}, {b: 3, c: 7}]) | ||
[Just(1), Just(4), Nothing()] | ||
> S.pluck('x', [{x: 1}, {x: 2}, {x: undefined}]) | ||
[Just(1), Just(2), Just(undefined)] | ||
``` | ||
### Object | ||
<h4 name="get"><code><a href="https://github.com/plaid/sanctuary/blob/v0.5.0/index.js#L1022">get :: String -> Object -> Maybe *</a></code></h4> | ||
Takes a property name and an object and returns Just the value of | ||
the specified property of the object if the object has such an own | ||
property; Nothing otherwise. | ||
```javascript | ||
> S.get('x', {x: 1, y: 2}) | ||
Just(1) | ||
> S.get('toString', {x: 1, y: 2}) | ||
Nothing() | ||
``` | ||
<h4 name="gets"><code><a href="https://github.com/plaid/sanctuary/blob/v0.5.0/index.js#L1037">gets :: [String] -> Object -> Maybe *</a></code></h4> | ||
Takes a list of property names and an object and returns Just the | ||
value at the path specified by the list of property names if such | ||
a path exists; Nothing otherwise. | ||
```javascript | ||
> S.gets(['a', 'b', 'c'], {a: {b: {c: 42}}}) | ||
Just(42) | ||
> S.gets(['a', 'b', 'c'], {}) | ||
Nothing() | ||
``` | ||
### Parse | ||
<h4 name="parseDate"><code><a href="https://github.com/plaid/sanctuary/blob/v0.5.0/index.js#L1058">parseDate :: String -> Maybe Date</a></code></h4> | ||
Takes a string and returns Just the date represented by the string | ||
if it does in fact represent a date; Nothing otherwise. | ||
```javascript | ||
> S.parseDate('2011-01-19T17:40:00Z') | ||
Just(new Date("2011-01-19T17:40:00.000Z")) | ||
> S.parseDate('today') | ||
Nothing() | ||
``` | ||
<h4 name="parseFloat"><code><a href="https://github.com/plaid/sanctuary/blob/v0.5.0/index.js#L1075">parseFloat :: String -> Maybe Number</a></code></h4> | ||
Takes a string and returns Just the number represented by the string | ||
if it does in fact represent a number; Nothing otherwise. | ||
```javascript | ||
> S.parseFloat('-123.45') | ||
Just(-123.45) | ||
> S.parseFloat('foo.bar') | ||
Nothing() | ||
``` | ||
<h4 name="parseInt"><code><a href="https://github.com/plaid/sanctuary/blob/v0.5.0/index.js#L1092">parseInt :: Number -> String -> Maybe Number</a></code></h4> | ||
Takes a radix (an integer between 2 and 36 inclusive) and a string, | ||
and returns Just the number represented by the string if it does in | ||
fact represent a number in the base specified by the radix; Nothing | ||
otherwise. | ||
```javascript | ||
> S.parseInt(16, '0xFF') | ||
Just(255) | ||
> S.parseInt(16, '0xGG') | ||
Nothing() | ||
``` | ||
<h4 name="parseJson"><code><a href="https://github.com/plaid/sanctuary/blob/v0.5.0/index.js#L1111">parseJson :: String -> Maybe *</a></code></h4> | ||
Takes a string which may or may not be valid JSON, and returns Just | ||
the result of applying `JSON.parse` to the string if valid; Nothing | ||
otherwise. | ||
```javascript | ||
> S.parseJson('["foo","bar","baz"]') | ||
Just(["foo", "bar", "baz"]) | ||
> S.parseJson('[') | ||
Nothing() | ||
``` | ||
### RegExp | ||
<h4 name="match"><code><a href="https://github.com/plaid/sanctuary/blob/v0.5.0/index.js#L1130">match :: RegExp -> String -> Maybe [Maybe String]</a></code></h4> | ||
Takes a pattern and a string, and returns Just a list of matches | ||
if the pattern matches the string; Nothing otherwise. Each match | ||
has type `Maybe String`, where a Nothing represents an unmatched | ||
optional capturing group. | ||
```javascript | ||
> S.match(/(good)?bye/, 'goodbye') | ||
Just([Just("goodbye"), Just("good")]) | ||
> S.match(/(good)?bye/, 'bye') | ||
Just([Just("bye"), Nothing()]) | ||
``` | ||
[Monad]: https://github.com/fantasyland/fantasy-land#monad | ||
[Monoid]: https://github.com/fantasyland/fantasy-land#monoid | ||
[R.map]: http://ramdajs.com/docs/#map | ||
[Ramda]: http://ramdajs.com/ | ||
[SameValue]: http://ecma-international.org/ecma-262/5.1/#sec-9.12 | ||
[Semigroup]: https://github.com/fantasyland/fantasy-land#semigroup |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
58423
1050
800
1
6
1
+ Addedramda@0.14.x
+ Addedramda@0.14.0(transitive)