Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

sanctuary

Package Overview
Dependencies
Maintainers
12
Versions
31
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

sanctuary

Refuge from unsafe JavaScript

  • 0.14.1
  • Source
  • npm
  • Socket score

Version published
Maintainers
12
Created
Source

Sanctuary

npm CircleCI Gitter

Sanctuary is a JavaScript functional programming library inspired by Haskell and PureScript. It's stricter than Ramda, and provides a similar suite of functions.

Sanctuary promotes programs composed of simple, pure functions. Such programs are easier to comprehend, test, and maintain – they are also a pleasure to write.

Sanctuary provides two data types, Maybe and Either, both of which are compatible with Fantasy Land. Thanks to these data types even Sanctuary functions which may fail, such as head, are composable.

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:

S.map(S.toUpper, S.head(words))

Sanctuary is designed to work in Node.js and in ES5-compatible browsers.

Types

Sanctuary uses Haskell-like type signatures to describe the types of values, including functions. 'foo', for example, is a member of String; [1, 2, 3] is a member of Array Number. The double colon (::) is used to mean "is a member of", so one could write:

'foo' :: String
[1, 2, 3] :: Array Number

An identifier may appear to the left of the double colon:

Math.PI :: Number

The arrow (->) is used to express a function's type:

Math.abs :: Number -> Number

That states that Math.abs is a unary function which takes an argument of type Number and returns a value of type Number.

Some functions are parametrically polymorphic: their types are not fixed. Type variables are used in the representations of such functions:

S.I :: a -> a

a is a type variable. Type variables are not capitalized, so they are differentiable from type identifiers (which are always capitalized). By convention type variables have single-character names. The signature above states that S.I takes a value of any type and returns a value of the same type. Some signatures feature multiple type variables:

S.K :: a -> b -> a

It must be possible to replace all occurrences of a with a concrete type. The same applies for each other type variable. For the function above, the types with which a and b are replaced may be different, but needn't be.

Since all Sanctuary functions are curried (they accept their arguments one at a time), a binary function is represented as a unary function which returns a unary function: * -> * -> *. This aligns neatly with Haskell, which uses curried functions exclusively. In JavaScript, though, we may wish to represent the types of functions with arities less than or greater than one. The general form is (<input-types>) -> <output-type>, where <input-types> comprises zero or more comma–space (, ) -separated type representations:

  • () -> String
  • (a, b) -> a
  • (a, b, c) -> d

Number -> Number can thus be seen as shorthand for (Number) -> Number.

The question mark (?) is used to represent types which include null and undefined as members. String?, for example, represents the type comprising null, undefined, and all strings.

Sanctuary embraces types. JavaScript doesn't support algebraic data types, but these can be simulated by providing a group of data constructors which return values with the same set of methods. A value of the Either type, for example, is created via the Left constructor or the Right 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 fantasy-land/map method of the Maybe type is written Maybe a ~> (a -> b) -> Maybe b. One could read this as:

When the fantasy-land/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.

The squiggly arrow is also used when representing non-function properties. Maybe a ~> Boolean, for example, represents a Boolean property of a value of type Maybe a.

Sanctuary supports type classes: constraints on type variables. Whereas a -> a implicitly supports every type, Functor f => (a -> b) -> f a -> f b requires that f be a type which satisfies the requirements of the Functor type class. Type-class constraints appear at the beginning of a type signature, separated from the rest of the signature by a fat arrow (=>).

Type representatives

What is the type of Number? One answer is a -> Number, since it's a function which takes an argument of any type and returns a Number value. When provided as the first argument to is, though, Number is really the value-level representative of the Number type.

Sanctuary uses the TypeRep pseudotype to describe type representatives. For example:

Number :: TypeRep Number

Number is the sole inhabitant of the TypeRep Number type.

Type checking

Sanctuary functions are defined via sanctuary-def to provide run-time type checking. This is tremendously useful during development: type errors are reported immediately, avoiding circuitous stack traces (at best) and silent failures due to type coercion (at worst). For example:

S.add(2, true);
// ! TypeError: Invalid value
//
//   add :: FiniteNumber -> FiniteNumber -> FiniteNumber
//                          ^^^^^^^^^^^^
//                               1
//
//   1)  true :: Boolean
//
//   The value at position 1 is not a member of ‘FiniteNumber’.
//
//   See https://github.com/sanctuary-js/sanctuary-def/tree/v0.14.0#FiniteNumber for information about the sanctuary-def/FiniteNumber type.

Compare this to the behaviour of Ramda's unchecked equivalent:

R.add(2, true);
// => 3

There is a performance cost to run-time type checking. One may wish to disable type checking in certain contexts to avoid paying this cost. create facilitates the creation of a Sanctuary module which does not perform type checking.

In Node, one could use an environment variable to determine whether to perform type checking:

const {create, env} = require('sanctuary');

const checkTypes = process.env.NODE_ENV !== 'production';
const S = create({checkTypes, env});

API

create :: { checkTypes :: Boolean, env :: Array Type } -⁠> Module

Takes an options record and returns a Sanctuary module. checkTypes specifies whether to enable type checking. The module's polymorphic functions (such as I) require each value associated with a type variable to be a member of at least one type in the environment.

A well-typed application of a Sanctuary function will produce the same result regardless of whether type checking is enabled. If type checking is enabled, a badly typed application will produce an exception with a descriptive error message.

The following snippet demonstrates defining a custom type and using create to produce a Sanctuary module which is aware of that type:

const {create, env} = require('sanctuary');
const $ = require('sanctuary-def');
const type = require('sanctuary-type-identifiers');

//    Identity :: a -> Identity a
const Identity = function Identity(x) {
  if (!(this instanceof Identity)) return new Identity(x);
  this.value = x;
};

Identity['@@type'] = 'my-package/Identity@1';

Identity.prototype['fantasy-land/map'] = function(f) {
  return Identity(f(this.value));
};

//    IdentityType :: Type -> Type
const IdentityType = $.UnaryType(
  Identity['@@type'],
  'http://example.com/my-package#Identity',
  x => type(x) === Identity['@@type'],
  identity => [identity.value]
);

const S = create({
  checkTypes: process.env.NODE_ENV !== 'production',
  env: env.concat([IdentityType($.Unknown)]),
});

S.map(S.sub(1), Identity(43));
// => Identity(42)

See also env.

env :: Array Type

The default environment, which may be used as is or as the basis of a custom environment in conjunction with create.

Placeholder

Sanctuary functions are designed with partial application in mind. In many cases one can define a more specific function in terms of a more general one simply by applying the more general function to some (but not all) of its arguments. For example, one could define sum :: Foldable f => f Number -> Number as S.reduce(S.add, 0).

In some cases, though, there are multiple orders in which one may wish to provide a function's arguments. S.concat('prefix') is a function which prefixes its argument, but how would one define a function which suffixes its argument? It's possible with the help of __, the special placeholder value.

The placeholder indicates a hole to be filled at some future time. The following are all equivalent (_ represents the placeholder):

  • f(x, y, z)
  • f(_, y, z)(x)
  • f(_, _, z)(x, y)
  • f(_, _, z)(_, y)(x)
__ :: Placeholder

The special placeholder value.

> S.map(S.concat('@'), ['foo', 'bar', 'baz'])
['@foo', '@bar', '@baz']

> S.map(S.concat(S.__, '?'), ['foo', 'bar', 'baz'])
['foo?', 'bar?', 'baz?']

Classify

type :: Any -⁠> { namespace :: Maybe String, name :: String, version :: NonNegativeInteger }

Returns the result of parsing the type identifier of the given value.

> S.type(S.Just(42))
{namespace: Just('sanctuary'), name: 'Maybe', version: 0}

> S.type([1, 2, 3])
{namespace: Nothing, name: 'Array', version: 0}
is :: TypeRep a -⁠> Any -⁠> Boolean

Takes a type representative and a value of any type and returns true iff the given value is of the specified type. Subtyping is not respected.

> S.is(Number, 42)
true

> S.is(Object, 42)
false

> S.is(String, 42)
false

Showable

toString :: Any -⁠> String

Alias of Z.toString.

> S.toString(-0)
'-0'

> S.toString(['foo', 'bar', 'baz'])
'["foo", "bar", "baz"]'

> S.toString({x: 1, y: 2, z: 3})
'{"x": 1, "y": 2, "z": 3}'

> S.toString(S.Left(S.Right(S.Just(S.Nothing))))
'Left(Right(Just(Nothing)))'

Fantasy Land

Sanctuary is compatible with the Fantasy Land specification.

equals :: Setoid a => a -⁠> a -⁠> Boolean

Curried version of Z.equals which requires two arguments of the same type.

To compare values of different types first use create to create a Sanctuary module with type checking disabled, then use that module's equals function.

> S.equals(0, -0)
true

> S.equals(NaN, NaN)
true

> S.equals(S.Just([1, 2, 3]), S.Just([1, 2, 3]))
true

> S.equals(S.Just([1, 2, 3]), S.Just([1, 2, 4]))
false
lt :: Ord a => a -⁠> (a -⁠> Boolean)

Returns true iff the second argument is less than the first according to Z.lt. The arguments must be provided one at a time.

See also lt_.

> S.filter(S.lt(3), [1, 2, 3, 4, 5])
[1, 2]
lt_ :: Ord a => a -⁠> a -⁠> Boolean

Returns true iff the first argument is less than the second according to Z.lt.

See also lt.

> S.lt_([1, 2, 3], [1, 2, 3])
false

> S.lt_([1, 2, 3], [1, 2, 4])
true

> S.lt_([1, 2, 3], [1, 2])
false
lte :: Ord a => a -⁠> (a -⁠> Boolean)

Returns true iff the second argument is less than or equal to the first according to Z.lte. The arguments must be provided one at a time.

See also lte_.

> S.filter(S.lte(3), [1, 2, 3, 4, 5])
[1, 2, 3]
lte_ :: Ord a => a -⁠> a -⁠> Boolean

Returns true iff the first argument is less than or equal to the second according to Z.lte.

See also lte.

> S.lte_([1, 2, 3], [1, 2, 3])
true

> S.lte_([1, 2, 3], [1, 2, 4])
true

> S.lte_([1, 2, 3], [1, 2])
false
gt :: Ord a => a -⁠> (a -⁠> Boolean)

Returns true iff the second argument is greater than the first according to Z.gt. The arguments must be provided one at a time.

See also gt_.

> S.filter(S.gt(3), [1, 2, 3, 4, 5])
[4, 5]
gt_ :: Ord a => a -⁠> a -⁠> Boolean

Returns true iff the first argument is greater than the second according to Z.gt.

See also gt.

> S.gt_([1, 2, 3], [1, 2, 3])
false

> S.gt_([1, 2, 3], [1, 2, 4])
false

> S.gt_([1, 2, 3], [1, 2])
true
gte :: Ord a => a -⁠> (a -⁠> Boolean)

Returns true iff the second argument is greater than or equal to the first according to Z.gte. The arguments must be provided one at a time.

See also gte_.

> S.filter(S.gte(3), [1, 2, 3, 4, 5])
[3, 4, 5]
gte_ :: Ord a => a -⁠> a -⁠> Boolean

Returns true iff the first argument is greater than or equal to the second according to Z.gte.

See also gte.

> S.gte_([1, 2, 3], [1, 2, 3])
true

> S.gte_([1, 2, 3], [1, 2, 4])
false

> S.gte_([1, 2, 3], [1, 2])
true
min :: Ord a => a -⁠> a -⁠> a

Returns the smaller of its two arguments (according to Z.lte).

See also max.

> S.min(10, 2)
2

> S.min(new Date('1999-12-31'), new Date('2000-01-01'))
new Date('1999-12-31')

> S.min('10', '2')
'10'
max :: Ord a => a -⁠> a -⁠> a

Returns the larger of its two arguments (according to Z.lte).

See also min.

> S.max(10, 2)
10

> S.max(new Date('1999-12-31'), new Date('2000-01-01'))
new Date('2000-01-01')

> S.max('10', '2')
'2'
id :: Category c => TypeRep c -⁠> c

Type-safe version of Z.id.

> S.id(Function)(42)
42
concat :: Semigroup a => a -⁠> a -⁠> a

Curried version of Z.concat.

> S.concat('abc', 'def')
'abcdef'

> S.concat([1, 2, 3], [4, 5, 6])
[1, 2, 3, 4, 5, 6]

> S.concat({x: 1, y: 2}, {y: 3, z: 4})
{x: 1, y: 3, z: 4}

> S.concat(S.Just([1, 2, 3]), S.Just([4, 5, 6]))
Just([1, 2, 3, 4, 5, 6])

> S.concat(Sum(18), Sum(24))
Sum(42)
empty :: Monoid a => TypeRep a -⁠> a

Type-safe version of Z.empty.

> S.empty(String)
''

> S.empty(Array)
[]

> S.empty(Object)
{}

> S.empty(Sum)
Sum(0)
invert :: Group g => g -⁠> g

Type-safe version of Z.invert.

> S.invert(Sum(5))
Sum(-5)
map :: Functor f => (a -⁠> b) -⁠> f a -⁠> f b

Curried version of Z.map.

> S.map(Math.sqrt, [1, 4, 9])
[1, 2, 3]

> S.map(Math.sqrt, {x: 1, y: 4, z: 9})
{x: 1, y: 2, z: 3}

> S.map(Math.sqrt, S.Just(9))
Just(3)

> S.map(Math.sqrt, S.Right(9))
Right(3)

Replacing Functor f => f with Function x produces the B combinator from combinatory logic (i.e. compose):

Functor f => (a -> b) -> f a -> f b
(a -> b) -> Function x a -> Function x b
(a -> c) -> Function x a -> Function x c
(b -> c) -> Function x b -> Function x c
(b -> c) -> Function a b -> Function a c
(b -> c) -> (a -> b) -> (a -> c)
> S.map(Math.sqrt, S.add(1))(99)
10
bimap :: Bifunctor f => (a -⁠> b) -⁠> (c -⁠> d) -⁠> f a c -⁠> f b d

Curried version of Z.bimap.

> S.bimap(S.toUpper, Math.sqrt, S.Left('foo'))
Left('FOO')

> S.bimap(S.toUpper, Math.sqrt, S.Right(64))
Right(8)
promap :: Profunctor p => (a -⁠> b) -⁠> (c -⁠> d) -⁠> p b c -⁠> p a d

Curried version of Z.promap.

> S.promap(Math.abs, S.add(1), Math.sqrt)(-100)
11
alt :: Alt f => f a -⁠> f a -⁠> f a

Curried version of Z.alt.

> S.alt(S.Nothing, S.Just(1))
Just(1)

> S.alt(S.Just(2), S.Just(3))
Just(2)

> S.alt(S.Left('X'), S.Right(1))
Right(1)

> S.alt(S.Right(2), S.Right(3))
Right(2)
zero :: Plus f => TypeRep f -⁠> f a

Type-safe version of Z.zero.

> S.zero(Array)
[]

> S.zero(Object)
{}

> S.zero(S.Maybe)
Nothing
reduce :: Foldable f => (b -⁠> a -⁠> b) -⁠> b -⁠> f a -⁠> b

Takes a curried binary function, an initial value, and a Foldable, and applies the function to the initial value and the Foldable's first value, then applies the function to the result of the previous application and the Foldable's second value. Repeats this process until each of the Foldable's values has been used. Returns the initial value if the Foldable is empty; the result of the final application otherwise.

> S.reduce(S.add, 0, [1, 2, 3, 4, 5])
15

> S.reduce(xs => x => [x].concat(xs), [], [1, 2, 3, 4, 5])
[5, 4, 3, 2, 1]
traverse :: (Applicative f, Traversable t) => TypeRep f -⁠> (a -⁠> f b) -⁠> t a -⁠> f (t b)

Curried version of Z.traverse.

> S.traverse(Array, S.words, S.Just('foo bar baz'))
[Just('foo'), Just('bar'), Just('baz')]

> S.traverse(Array, S.words, S.Nothing)
[Nothing]

> S.traverse(S.Maybe, S.parseInt(16), ['A', 'B', 'C'])
Just([10, 11, 12])

> S.traverse(S.Maybe, S.parseInt(16), ['A', 'B', 'C', 'X'])
Nothing

> S.traverse(S.Maybe, S.parseInt(16), {a: 'A', b: 'B', c: 'C'})
Just({a: 10, b: 11, c: 12})

> S.traverse(S.Maybe, S.parseInt(16), {a: 'A', b: 'B', c: 'C', x: 'X'})
Nothing
sequence :: (Applicative f, Traversable t) => TypeRep f -⁠> t (f a) -⁠> f (t a)

Curried version of Z.sequence. Inverts the given t (f a) to produce an f (t a).

> S.sequence(Array, S.Just([1, 2, 3]))
[Just(1), Just(2), Just(3)]

> S.sequence(S.Maybe, [S.Just(1), S.Just(2), S.Just(3)])
Just([1, 2, 3])

> S.sequence(S.Maybe, [S.Just(1), S.Just(2), S.Nothing])
Nothing

> S.sequence(S.Maybe, {a: S.Just(1), b: S.Just(2), c: S.Just(3)})
Just({a: 1, b: 2, c: 3})

> S.sequence(S.Maybe, {a: S.Just(1), b: S.Just(2), c: S.Nothing})
Nothing
ap :: Apply f => f (a -⁠> b) -⁠> f a -⁠> f b

Curried version of Z.ap.

> S.ap([Math.sqrt, x => x * x], [1, 4, 9, 16, 25])
[1, 2, 3, 4, 5, 1, 16, 81, 256, 625]

> S.ap({x: Math.sqrt, y: S.add(1), z: S.sub(1)}, {w: 4, x: 4, y: 4})
{x: 2, y: 5}

> S.ap(S.Just(Math.sqrt), S.Just(64))
Just(8)

Replacing Apply f => f with Function x produces the S combinator from combinatory logic:

Apply f => f (a -> b) -> f a -> f b
Function x (a -> b) -> Function x a -> Function x b
Function x (a -> c) -> Function x a -> Function x c
Function x (b -> c) -> Function x b -> Function x c
Function a (b -> c) -> Function a b -> Function a c
(a -> b -> c) -> (a -> b) -> (a -> c)
> S.ap(s => n => s.slice(0, n), s => Math.ceil(s.length / 2))('Haskell')
'Hask'
lift2 :: Apply f => (a -⁠> b -⁠> c) -⁠> f a -⁠> f b -⁠> f c

Promotes a curried binary function to a function which operates on two Applys.

> S.lift2(S.add, S.Just(2), S.Just(3))
Just(5)

> S.lift2(S.add, S.Just(2), S.Nothing)
Nothing

> S.lift2(S.and, S.Just(true), S.Just(true))
Just(true)

> S.lift2(S.and, S.Just(true), S.Just(false))
Just(false)
lift3 :: Apply f => (a -⁠> b -⁠> c -⁠> d) -⁠> f a -⁠> f b -⁠> f c -⁠> f d

Promotes a curried ternary function to a function which operates on three Applys.

> S.lift3(S.reduce, S.Just(S.add), S.Just(0), S.Just([1, 2, 3]))
Just(6)

> S.lift3(S.reduce, S.Just(S.add), S.Just(0), S.Nothing)
Nothing
apFirst :: Apply f => f a -⁠> f b -⁠> f a

Curried version of Z.apFirst. Combines two effectful actions, keeping only the result of the first. Equivalent to Haskell's (<*) function.

See also apSecond.

> S.apFirst([1, 2], [3, 4])
[1, 1, 2, 2]

> S.apFirst(S.Just(1), S.Just(2))
Just(1)
apSecond :: Apply f => f a -⁠> f b -⁠> f b

Curried version of Z.apSecond. Combines two effectful actions, keeping only the result of the second. Equivalent to Haskell's (*>) function.

See also apFirst.

> S.apSecond([1, 2], [3, 4])
[3, 4, 3, 4]

> S.apSecond(S.Just(1), S.Just(2))
Just(2)
of :: Applicative f => TypeRep f -⁠> a -⁠> f a

Curried version of Z.of.

> S.of(Array, 42)
[42]

> S.of(Function, 42)(null)
42

> S.of(S.Maybe, 42)
Just(42)

> S.of(S.Either, 42)
Right(42)
chain :: Chain m => (a -⁠> m b) -⁠> m a -⁠> m b

Curried version of Z.chain.

> S.chain(x => [x, x], [1, 2, 3])
[1, 1, 2, 2, 3, 3]

> S.chain(n => s => s.slice(0, n), s => Math.ceil(s.length / 2))('slice')
'sli'

> S.chain(S.parseInt(10), S.Just('123'))
Just(123)

> S.chain(S.parseInt(10), S.Just('XXX'))
Nothing
join :: Chain m => m (m a) -⁠> m a

Type-safe version of Z.join. Removes one level of nesting from a nested monadic structure.

> S.join([[1], [2], [3]])
[1, 2, 3]

> S.join([[[1, 2, 3]]])
[[1, 2, 3]]

> S.join(S.Just(S.Just(1)))
S.Just(1)

Replacing Chain m => m with Function x produces the W combinator from combinatory logic:

Chain m => m (m a) -> m a
Function x (Function x a) -> Function x a
(x -> x -> a) -> (x -> a)
> S.join(S.concat)('abc')
'abcabc'
chainRec :: ChainRec m => TypeRep m -⁠> (a -⁠> m (Either a b)) -⁠> a -⁠> m b

Performs a chain-like computation with constant stack usage. Similar to Z.chainRec, but curried and more convenient due to the use of the Either type to indicate completion (via a Right).

> S.chainRec(Array,
.            s => s.length === 2 ? S.map(S.Right, [s + '!', s + '?'])
.                                : S.map(S.Left, [s + 'o', s + 'n']),
.            '')
['oo!', 'oo?', 'on!', 'on?', 'no!', 'no?', 'nn!', 'nn?']
extend :: Extend w => (w a -⁠> b) -⁠> w a -⁠> w b

Curried version of Z.extend.

> S.extend(S.joinWith(''), ['x', 'y', 'z'])
['xyz', 'yz', 'z']
extract :: Comonad w => w a -⁠> a

Type-safe version of Z.extract.

contramap :: Contravariant f => (b -⁠> a) -⁠> f a -⁠> f b

Type-safe version of Z.contramap.

> S.contramap(s => s.length, Math.sqrt)('Sanctuary')
3
filter :: (Applicative f, Foldable f, Monoid (f a)) => (a -⁠> Boolean) -⁠> f a -⁠> f a

Curried version of Z.filter. Filters its second argument in accordance with the given predicate.

See also filterM.

> S.filter(S.odd, [1, 2, 3, 4, 5])
[1, 3, 5]
filterM :: (Alternative m, Monad m) => (a -⁠> Boolean) -⁠> m a -⁠> m a

Curried version of Z.filterM. Filters its second argument in accordance with the given predicate.

See also filter.

> S.filterM(S.odd, [1, 2, 3, 4, 5])
[1, 3, 5]

> S.filterM(S.odd, S.Just(9))
Just(9)

> S.filterM(S.odd, S.Just(4))
Nothing
takeWhile :: (Foldable f, Alternative f) => (a -⁠> Boolean) -⁠> f a -⁠> f a

Discards the first inner value which does not satisfy the predicate, and all subsequent inner values.

> S.takeWhile(S.odd, [3, 3, 3, 7, 6, 3, 5, 4])
[3, 3, 3, 7]

> S.takeWhile(S.even, [3, 3, 3, 7, 6, 3, 5, 4])
[]
dropWhile :: (Foldable f, Alternative f) => (a -⁠> Boolean) -⁠> f a -⁠> f a

Retains the first inner value which does not satisfy the predicate, and all subsequent inner values.

> S.dropWhile(S.odd, [3, 3, 3, 7, 6, 3, 5, 4])
[6, 3, 5, 4]

> S.dropWhile(S.even, [3, 3, 3, 7, 6, 3, 5, 4])
[3, 3, 3, 7, 6, 3, 5, 4]

Combinator

I :: a -⁠> a

The I combinator. Returns its argument. Equivalent to Haskell's id function.

> S.I('foo')
'foo'
K :: a -⁠> b -⁠> a

The K combinator. Takes two values and returns the first. Equivalent to Haskell's const function.

> S.K('foo', 'bar')
'foo'

> S.map(S.K(42), S.range(0, 5))
[42, 42, 42, 42, 42]
A :: (a -⁠> b) -⁠> a -⁠> b

The A combinator. Takes a function and a value, and returns the result of applying the function to the value. Equivalent to Haskell's ($) function.

> S.A(S.add(1), 42)
43

> S.map(S.A(S.__, 100), [S.add(1), Math.sqrt])
[101, 10]
T :: a -⁠> (a -⁠> b) -⁠> b

The T (thrush) combinator. Takes a value and a function, and returns the result of applying the function to the value. Equivalent to Haskell's (&) function.

> S.T(42, S.add(1))
43

> S.map(S.T(100), [S.add(1), Math.sqrt])
[101, 10]

Function

curry2 :: ((a, b) -⁠> c) -⁠> a -⁠> b -⁠> c

Curries the given binary function.

> S.map(S.curry2(Math.pow)(10), [1, 2, 3])
[10, 100, 1000]

> S.map(S.curry2(Math.pow, 10), [1, 2, 3])
[10, 100, 1000]
curry3 :: ((a, b, c) -⁠> d) -⁠> a -⁠> b -⁠> c -⁠> d

Curries the given ternary function.

> global.replaceString = S.curry3((what, replacement, string) =>
.   string.replace(what, replacement)
. )
replaceString

> replaceString('banana')('orange')('banana icecream')
'orange icecream'

> replaceString('banana', 'orange', 'banana icecream')
'orange icecream'
curry4 :: ((a, b, c, d) -⁠> e) -⁠> a -⁠> b -⁠> c -⁠> d -⁠> e

Curries the given quaternary function.

> global.createRect = S.curry4((x, y, width, height) =>
.   ({x, y, width, height})
. )
createRect

> createRect(0)(0)(10)(10)
{x: 0, y: 0, width: 10, height: 10}

> createRect(0, 0, 10, 10)
{x: 0, y: 0, width: 10, height: 10}
curry5 :: ((a, b, c, d, e) -⁠> f) -⁠> a -⁠> b -⁠> c -⁠> d -⁠> e -⁠> f

Curries the given quinary function.

> global.toUrl = S.curry5((protocol, creds, hostname, port, pathname) =>
.   protocol + '//' +
.   S.maybe('', _ => _.username + ':' + _.password + '@', creds) +
.   hostname +
.   S.maybe('', S.concat(':'), port) +
.   pathname
. )
toUrl

> toUrl('https:')(S.Nothing)('example.com')(S.Just('443'))('/foo/bar')
'https://example.com:443/foo/bar'

> toUrl('https:', S.Nothing, 'example.com', S.Just('443'), '/foo/bar')
'https://example.com:443/foo/bar'
flip :: (a -⁠> b -⁠> c) -⁠> b -⁠> a -⁠> c

Takes a curried binary function and two values, and returns the result of applying the function to the values in reverse order.

This is the C combinator from combinatory logic.

> S.flip(S.concat, 'foo', 'bar')
'barfoo'

Composition

compose :: Semigroupoid s => s b c -⁠> s a b -⁠> s a c

Curried version of Z.compose.

When specialized to Function, compose composes two unary functions, from right to left (this is the B combinator from combinatory logic).

The generalized type signature indicates that compose is compatible with any Semigroupoid.

See also pipe.

> S.compose(Math.sqrt, S.add(1))(99)
10
pipe :: [(a -⁠> b), (b -⁠> c), ..., (m -⁠> n)] -⁠> a -⁠> n

Takes an array of functions assumed to be unary and a value of any type, and returns the result of applying the sequence of transformations to the initial value.

In general terms, pipe performs left-to-right composition of an array of functions. pipe([f, g, h], x) is equivalent to h(g(f(x))).

> S.pipe([S.add(1), Math.sqrt, S.sub(1)], 99)
9
on :: (b -⁠> b -⁠> c) -⁠> (a -⁠> b) -⁠> a -⁠> a -⁠> c

Takes a binary function f, a unary function g, and two values x and y. Returns f(g(x))(g(y)).

This is the P combinator from combinatory logic.

> S.on(S.concat, S.reverse, [1, 2, 3], [4, 5, 6])
[3, 2, 1, 6, 5, 4]

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 Nothing (with no value).

The Maybe type satisfies the Ord, Monoid, Monad, Alternative, Traversable, and Extend specifications.

MaybeType :: Type -⁠> Type

A UnaryType for use with sanctuary-def.

Maybe :: TypeRep Maybe

The type representative for the Maybe type.

Nothing :: Maybe a

Nothing.

> S.Nothing
Nothing
Just :: a -⁠> Maybe a

Takes a value of any type and returns a Just with the given value.

> S.Just(42)
Just(42)
Maybe.@@type :: String

Maybe type identifier, 'sanctuary/Maybe'.

Maybe.fantasy-land/empty :: () -⁠> Maybe a

Returns Nothing.

It is idiomatic to use empty rather than use this function directly.

> S.empty(S.Maybe)
Nothing
Maybe.fantasy-land/of :: a -⁠> Maybe a

Takes a value of any type and returns a Just with the given value.

It is idiomatic to use of rather than use this function directly.

> S.of(S.Maybe, 42)
Just(42)
Maybe.fantasy-land/zero :: () -⁠> Maybe a

Returns Nothing.

It is idiomatic to use zero rather than use this function directly.

> S.zero(S.Maybe)
Nothing
Maybe#isNothing :: Maybe a ~> Boolean

true if this is Nothing; false if this is a Just.

> S.Nothing.isNothing
true

> S.Just(42).isNothing
false
Maybe#isJust :: Maybe a ~> Boolean

true if this is a Just; false if this is Nothing.

> S.Just(42).isJust
true

> S.Nothing.isJust
false
Maybe#toString :: Maybe a ~> () -⁠> String

Returns the string representation of the Maybe.

> S.toString(S.Nothing)
'Nothing'

> S.toString(S.Just([1, 2, 3]))
'Just([1, 2, 3])'
Maybe#inspect :: Maybe a ~> () -⁠> String

Returns the string representation of the Maybe. This method is used by util.inspect and the REPL to format a Maybe for display.

See also Maybe#toString.

> S.Nothing.inspect()
'Nothing'

> S.Just([1, 2, 3]).inspect()
'Just([1, 2, 3])'
Maybe#fantasy-land/equals :: Setoid a => Maybe a ~> Maybe a -⁠> Boolean

Takes a value m of the same type and returns true if:

  • this and m are both Nothing; or

  • this and m are both Justs, and their values are equal according to Z.equals.

It is idiomatic to use equals rather than use this method directly.

> S.equals(S.Nothing, S.Nothing)
true

> S.equals(S.Just([1, 2, 3]), S.Just([1, 2, 3]))
true

> S.equals(S.Just([1, 2, 3]), S.Just([3, 2, 1]))
false

> S.equals(S.Just([1, 2, 3]), S.Nothing)
false
Maybe#fantasy-land/lte :: Ord a => Maybe a ~> Maybe a -⁠> Boolean

Takes a value m of the same type and returns true if:

  • this is Nothing; or

  • this and m are both Justs and the value of this is less than or equal to the value of m according to Z.lte.

It is idiomatic to use lte or lte_ rather than use this method directly.

> S.lte_(S.Nothing, S.Nothing)
true

> S.lte_(S.Nothing, S.Just(0))
true

> S.lte_(S.Just(0), S.Nothing)
false

> S.lte_(S.Just(0), S.Just(1))
true

> S.lte_(S.Just(1), S.Just(0))
false
Maybe#fantasy-land/concat :: Semigroup a => Maybe a ~> Maybe a -⁠> Maybe a

Returns the result of concatenating two Maybe values of the same type. a must have a Semigroup.

If this is Nothing and the argument is Nothing, this method returns 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.

It is idiomatic to use concat rather than use this method directly.

> S.concat(S.Nothing, S.Nothing)
Nothing

> S.concat(S.Just([1, 2, 3]), S.Just([4, 5, 6]))
Just([1, 2, 3, 4, 5, 6])

> S.concat(S.Nothing, S.Just([1, 2, 3]))
Just([1, 2, 3])

> S.concat(S.Just([1, 2, 3]), S.Nothing)
Just([1, 2, 3])
Maybe#fantasy-land/map :: Maybe a ~> (a -⁠> b) -⁠> Maybe b

Takes a function and returns this if this is Nothing; otherwise it returns a Just whose value is the result of applying the function to this Just's value.

It is idiomatic to use map rather than use this method directly.

> S.map(Math.sqrt, S.Nothing)
Nothing

> S.map(Math.sqrt, S.Just(9))
Just(3)
Maybe#fantasy-land/ap :: Maybe a ~> Maybe (a -⁠> b) -⁠> Maybe b

Takes a Maybe and returns 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 applying the given Just's value to this Just's value.

It is idiomatic to use ap rather than use this method directly.

> S.ap(S.Nothing, S.Nothing)
Nothing

> S.ap(S.Nothing, S.Just(9))
Nothing

> S.ap(S.Just(Math.sqrt), S.Nothing)
Nothing

> S.ap(S.Just(Math.sqrt), S.Just(9))
Just(3)
Maybe#fantasy-land/chain :: Maybe a ~> (a -⁠> Maybe b) -⁠> Maybe b

Takes a function and returns this if this is Nothing; otherwise it returns the result of applying the function to this Just's value.

It is idiomatic to use chain rather than use this method directly.

> S.chain(S.parseFloat, S.Nothing)
Nothing

> S.chain(S.parseFloat, S.Just('xxx'))
Nothing

> S.chain(S.parseFloat, S.Just('12.34'))
Just(12.34)
Maybe#fantasy-land/alt :: Maybe a ~> Maybe a -⁠> Maybe a

Chooses between this and the other Maybe provided as an argument. Returns this if this is a Just; the other Maybe otherwise.

It is idiomatic to use alt rather than use this method directly.

> S.alt(S.Nothing, S.Nothing)
Nothing

> S.alt(S.Nothing, S.Just(1))
Just(1)

> S.alt(S.Just(2), S.Nothing)
Just(2)

> S.alt(S.Just(3), S.Just(4))
Just(3)
Maybe#fantasy-land/reduce :: Maybe a ~> ((b, a) -⁠> b, b) -⁠> b

Takes a function and an initial value of any type, and returns:

  • the initial value if this is Nothing; otherwise

  • the result of applying the function to the initial value and this Just's value.

It is idiomatic to use reduce rather than use this method directly.

> S.reduce(S.curry2(Math.pow), 10, S.Nothing)
10

> S.reduce(S.curry2(Math.pow), 10, S.Just(3))
1000
Maybe#fantasy-land/traverse :: Applicative f => Maybe a ~> (TypeRep f, a -⁠> f b) -⁠> f (Maybe b)

Takes the type representative of some Applicative and a function which returns a value of that Applicative, and returns:

  • the result of applying the type representative's of function to this if this is Nothing; otherwise

  • the result of mapping Just over the result of applying the first function to this Just's value.

It is idiomatic to use traverse rather than use this method directly.

> S.traverse(Array, S.words, S.Nothing)
[Nothing]

> S.traverse(Array, S.words, S.Just('foo bar baz'))
[Just('foo'), Just('bar'), Just('baz')]
Maybe#fantasy-land/extend :: Maybe a ~> (Maybe a -⁠> b) -⁠> Maybe b

Takes a function and returns this if this is Nothing; otherwise it returns a Just whose value is the result of applying the function to this.

It is idiomatic to use extend rather than use this method directly.

> S.extend(x => x.value + 1, S.Nothing)
Nothing

> S.extend(x => x.value + 1, S.Just(42))
Just(43)
isNothing :: Maybe a -⁠> Boolean

Returns true if the given Maybe is Nothing; false if it is a Just.

> S.isNothing(S.Nothing)
true

> S.isNothing(S.Just(42))
false
isJust :: Maybe a -⁠> Boolean

Returns true if the given Maybe is a Just; false if it is Nothing.

> S.isJust(S.Just(42))
true

> S.isJust(S.Nothing)
false
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.

See also fromMaybe_ and maybeToNullable.

> S.fromMaybe(0, S.Just(42))
42

> S.fromMaybe(0, S.Nothing)
0
fromMaybe_ :: (() -⁠> a) -⁠> Maybe a -⁠> a

Variant of fromMaybe which takes a thunk so the default value is only computed if required.

> function fib(n) { return n <= 1 ? n : fib(n - 2) + fib(n - 1); }

> S.fromMaybe_(() => fib(30), S.Just(1000000))
1000000

> S.fromMaybe_(() => fib(30), S.Nothing)
832040
maybeToNullable :: Maybe a -⁠> Nullable a

Returns the given Maybe's value if the Maybe is a Just; null otherwise. Nullable is defined in sanctuary-def.

See also fromMaybe.

> S.maybeToNullable(S.Just(42))
42

> S.maybeToNullable(S.Nothing)
null
toMaybe :: a? -⁠> Maybe a

Takes a value and returns Nothing if the value is null or undefined; Just the value otherwise.

> S.toMaybe(null)
Nothing

> S.toMaybe(42)
Just(42)
maybe :: b -⁠> (a -⁠> b) -⁠> Maybe a -⁠> b

Takes a value of any type, a function, and a Maybe. If the Maybe is a Just, the return value is the result of applying the function to the Just's value. Otherwise, the first argument is returned.

See also maybe_.

> S.maybe(0, S.prop('length'), S.Just('refuge'))
6

> S.maybe(0, S.prop('length'), S.Nothing)
0
maybe_ :: (() -⁠> b) -⁠> (a -⁠> b) -⁠> Maybe a -⁠> b

Variant of maybe which takes a thunk so the default value is only computed if required.

> function fib(n) { return n <= 1 ? n : fib(n - 2) + fib(n - 1); }

> S.maybe_(() => fib(30), Math.sqrt, S.Just(1000000))
1000

> S.maybe_(() => fib(30), Math.sqrt, S.Nothing)
832040
justs :: Array (Maybe a) -⁠> Array a

Takes an array of Maybes and returns an array containing each Just's value. Equivalent to Haskell's catMaybes function.

See also lefts and rights.

> S.justs([S.Just('foo'), S.Nothing, S.Just('baz')])
['foo', 'baz']
mapMaybe :: (a -⁠> Maybe b) -⁠> Array a -⁠> Array b

Takes a function and an array, applies the function to each element of the array, and returns an array of "successful" results. If the result of applying the function to an element of the array is Nothing, the result is discarded; if the result is a Just, the Just's value is included in the output array.

In general terms, mapMaybe filters an array while mapping over it.

> S.mapMaybe(S.head, [[], [1, 2, 3], [], [4, 5, 6], []])
[1, 4]
encase :: (a -⁠> b) -⁠> a -⁠> Maybe b

Takes a unary function f which may throw and a value x of any type, and applies f to x inside a try block. If an exception is caught, the return value is Nothing; otherwise the return value is Just the result of applying f to x.

See also encaseEither.

> S.encase(eval, '1 + 1')
Just(2)

> S.encase(eval, '1 +')
Nothing
encase2 :: (a -⁠> b -⁠> c) -⁠> a -⁠> b -⁠> Maybe c

Binary version of encase.

encase3 :: (a -⁠> b -⁠> c -⁠> d) -⁠> a -⁠> b -⁠> c -⁠> Maybe d

Ternary version of encase.

maybeToEither :: a -⁠> Maybe b -⁠> Either a b

Converts a Maybe to an Either. Nothing becomes a Left (containing the first argument); a Just becomes a Right.

See also eitherToMaybe.

> S.maybeToEither('Expecting an integer', S.parseInt(10, 'xyz'))
Left('Expecting an integer')

> S.maybeToEither('Expecting an integer', S.parseInt(10, '42'))
Right(42)

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 Ord, Semigroup, Monad, Alt, Traversable, Extend, and Bifunctor specifications.

EitherType :: Type -⁠> Type -⁠> Type

A BinaryType for use with sanctuary-def.

Either :: TypeRep Either

The type representative for the Either type.

Left :: a -⁠> Either a b

Takes a value of any type and returns a Left with the given value.

> S.Left('Cannot divide by zero')
Left('Cannot divide by zero')
Right :: b -⁠> Either a b

Takes a value of any type and returns a Right with the given value.

> S.Right(42)
Right(42)
Either.@@type :: String

Either type identifier, 'sanctuary/Either'.

Either.fantasy-land/of :: b -⁠> Either a b

Takes a value of any type and returns a Right with the given value.

It is idiomatic to use of rather than use this function directly.

> S.of(S.Either, 42)
Right(42)
Either#isLeft :: Either a b ~> Boolean

true if this is a Left; false if this is a Right.

> S.Left('Cannot divide by zero').isLeft
true

> S.Right(42).isLeft
false
Either#isRight :: Either a b ~> Boolean

true if this is a Right; false if this is a Left.

> S.Right(42).isRight
true

> S.Left('Cannot divide by zero').isRight
false
Either#toString :: Either a b ~> () -⁠> String

Returns the string representation of the Either.

> S.toString(S.Left('Cannot divide by zero'))
'Left("Cannot divide by zero")'

> S.toString(S.Right([1, 2, 3]))
'Right([1, 2, 3])'
Either#inspect :: Either a b ~> () -⁠> String

Returns the string representation of the Either. This method is used by util.inspect and the REPL to format a Either for display.

See also Either#toString.

> S.Left('Cannot divide by zero').inspect()
'Left("Cannot divide by zero")'

> S.Right([1, 2, 3]).inspect()
'Right([1, 2, 3])'
Either#fantasy-land/equals :: (Setoid a, Setoid b) => Either a b ~> Either a b -⁠> Boolean

Takes a value e of the same type and returns true if:

  • this and e are both Lefts or both Rights, and their values are equal according to Z.equals.

It is idiomatic to use equals rather than use this method directly.

> S.equals(S.Right([1, 2, 3]), S.Right([1, 2, 3]))
true

> S.equals(S.Right([1, 2, 3]), S.Left([1, 2, 3]))
false
Either#fantasy-land/lte :: (Ord a, Ord b) => Either a b ~> Either a b -⁠> Boolean

Takes a value e of the same type and returns true if:

  • this is a Left and e is a Right; or

  • this and e are both Lefts or both Rights, and the value of this is less than or equal to the value of e according to Z.lte.

It is idiomatic to use lte or lte_ rather than use this method directly.

> S.lte_(S.Left(10), S.Right(0))
true

> S.lte_(S.Right(0), S.Left(10))
false

> S.lte_(S.Right(0), S.Right(1))
true

> S.lte_(S.Right(1), S.Right(0))
false
Either#fantasy-land/concat :: (Semigroup a, Semigroup b) => 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, 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.

It is idiomatic to use concat rather than use this method directly.

> S.concat(S.Left('abc'), S.Left('def'))
Left('abcdef')

> S.concat(S.Right([1, 2, 3]), S.Right([4, 5, 6]))
Right([1, 2, 3, 4, 5, 6])

> S.concat(S.Left('abc'), S.Right([1, 2, 3]))
Right([1, 2, 3])

> S.concat(S.Right([1, 2, 3]), S.Left('abc'))
Right([1, 2, 3])
Either#fantasy-land/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.

It is idiomatic to use map rather than use this method directly.

See also Either#fantasy-land/bimap.

> S.map(Math.sqrt, S.Left('Cannot divide by zero'))
Left('Cannot divide by zero')

> S.map(Math.sqrt, S.Right(9))
Right(3)
Either#fantasy-land/bimap :: Either a b ~> (a -⁠> c, b -⁠> d) -⁠> Either c d

Takes two functions and returns:

  • a Left whose value is the result of applying the first function to this Left's value if this is a Left; otherwise

  • a Right whose value is the result of applying the second function to this Right's value.

Similar to Either#fantasy-land/map, but supports mapping over the left side as well as the right side.

It is idiomatic to use bimap rather than use this method directly.

> S.bimap(S.toUpper, S.add(1), S.Left('abc'))
Left('ABC')

> S.bimap(S.toUpper, S.add(1), S.Right(42))
Right(43)
Either#fantasy-land/ap :: Either a b ~> Either a (b -⁠> c) -⁠> Either a c

Takes an Either 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 the given Right's value to this Right's value.

It is idiomatic to use ap rather than use this method directly.

> S.ap(S.Left('No such function'), S.Left('Cannot divide by zero'))
Left('No such function')

> S.ap(S.Left('No such function'), S.Right(9))
Left('No such function')

> S.ap(S.Right(Math.sqrt), S.Left('Cannot divide by zero'))
Left('Cannot divide by zero')

> S.ap(S.Right(Math.sqrt), S.Right(9))
Right(3)
Either#fantasy-land/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.

It is idiomatic to use chain rather than use this method directly.

> global.sqrt = n =>
.   n < 0 ? S.Left('Cannot represent square root of negative number')
.         : S.Right(Math.sqrt(n))
sqrt

> S.chain(sqrt, S.Left('Cannot divide by zero'))
Left('Cannot divide by zero')

> S.chain(sqrt, S.Right(-1))
Left('Cannot represent square root of negative number')

> S.chain(sqrt, S.Right(25))
Right(5)
Either#fantasy-land/alt :: Either a b ~> Either a b -⁠> Either a b

Chooses between this and the other Either provided as an argument. Returns this if this is a Right; the other Either otherwise.

It is idiomatic to use alt rather than use this method directly.

> S.alt(S.Left('A'), S.Left('B'))
Left('B')

> S.alt(S.Left('C'), S.Right(1))
Right(1)

> S.alt(S.Right(2), S.Left('D'))
Right(2)

> S.alt(S.Right(3), S.Right(4))
Right(3)
Either#fantasy-land/reduce :: Either a b ~> ((c, b) -⁠> c, c) -⁠> c

Takes a function and an initial value of any type, and returns:

  • the initial value if this is a Left; otherwise

  • the result of applying the function to the initial value and this Right's value.

It is idiomatic to use reduce rather than use this method directly.

> S.reduce(S.curry2(Math.pow), 10, S.Left('Cannot divide by zero'))
10

> S.reduce(S.curry2(Math.pow), 10, S.Right(3))
1000
Either#fantasy-land/traverse :: Applicative f => Either a b ~> (TypeRep f, b -⁠> f c) -⁠> f (Either a c)

Takes the type representative of some Applicative and a function which returns a value of that Applicative, and returns:

  • the result of applying the type representative's of function to this if this is a Left; otherwise

  • the result of mapping Right over the result of applying the first function to this Right's value.

It is idiomatic to use traverse rather than use this method directly.

> S.traverse(Array, S.words, S.Left('Request failed'))
[Left('Request failed')]

> S.traverse(Array, S.words, S.Right('foo bar baz'))
[Right('foo'), Right('bar'), Right('baz')]
Either#fantasy-land/extend :: Either a b ~> (Either a 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.

It is idiomatic to use extend rather than use this method directly.

> S.extend(x => x.value + 1, S.Left('Cannot divide by zero'))
Left('Cannot divide by zero')

> S.extend(x => x.value + 1, S.Right(42))
Right(43)
isLeft :: Either a b -⁠> Boolean

Returns true if the given Either is a Left; false if it is a Right.

> S.isLeft(S.Left('Cannot divide by zero'))
true

> S.isLeft(S.Right(42))
false
isRight :: Either a b -⁠> Boolean

Returns true if the given Either is a Right; false if it is a Left.

> S.isRight(S.Right(42))
true

> S.isRight(S.Left('Cannot divide by zero'))
false
fromEither :: b -⁠> Either a b -⁠> b

Takes a default value and an Either, and returns the Right value if the Either is a Right; the default value otherwise.

> S.fromEither(0, S.Right(42))
42

> S.fromEither(0, S.Left(42))
0
toEither :: a -⁠> b? -⁠> Either a b

Converts an arbitrary value to an Either: a Left if the value is null or undefined; a Right otherwise. The first argument specifies the value of the Left in the "failure" case.

> S.toEither('XYZ', null)
Left('XYZ')

> S.toEither('XYZ', 'ABC')
Right('ABC')

> S.map(S.prop('0'), S.toEither('Invalid protocol', 'ftp://example.com/'.match(/^https?:/)))
Left('Invalid protocol')

> S.map(S.prop('0'), S.toEither('Invalid protocol', 'https://example.com/'.match(/^https?:/)))
Right('https:')
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.

> S.either(S.toUpper, S.toString, S.Left('Cannot divide by zero'))
'CANNOT DIVIDE BY ZERO'

> S.either(S.toUpper, S.toString, S.Right(42))
'42'
lefts :: Array (Either a b) -⁠> Array a

Takes an array of Eithers and returns an array containing each Left's value.

See also rights.

> S.lefts([S.Right(20), S.Left('foo'), S.Right(10), S.Left('bar')])
['foo', 'bar']
rights :: Array (Either a b) -⁠> Array b

Takes an array of Eithers and returns an array containing each Right's value.

See also lefts.

> S.rights([S.Right(20), S.Left('foo'), S.Right(10), S.Left('bar')])
[20, 10]
tagBy :: (a -⁠> Boolean) -⁠> a -⁠> Either a a

Takes a predicate and a value, and returns a Right of the value if it satisfies the predicate; a Left of the value otherwise.

> S.tagBy(S.odd, 0)
Left(0)

> S.tagBy(S.odd, 1)
Right(1)
encaseEither :: (Error -⁠> l) -⁠> (a -⁠> r) -⁠> a -⁠> Either l r

Takes two unary functions, f and g, the second of which may throw, and a value x of any type. Applies g to x inside a try block. If an exception is caught, the return value is a Left containing the result of applying f to the caught Error object; otherwise the return value is a Right containing the result of applying g to x.

See also encase.

> S.encaseEither(S.I, JSON.parse, '["foo","bar","baz"]')
Right(['foo', 'bar', 'baz'])

> S.encaseEither(S.I, JSON.parse, '[')
Left(new SyntaxError('Unexpected end of JSON input'))

> S.encaseEither(S.prop('message'), JSON.parse, '[')
Left('Unexpected end of JSON input')
encaseEither2 :: (Error -⁠> l) -⁠> (a -⁠> b -⁠> r) -⁠> a -⁠> b -⁠> Either l r

Binary version of encaseEither.

encaseEither3 :: (Error -⁠> l) -⁠> (a -⁠> b -⁠> c -⁠> r) -⁠> a -⁠> b -⁠> c -⁠> Either l r

Ternary version of encaseEither.

eitherToMaybe :: Either a b -⁠> Maybe b

Converts an Either to a Maybe. A Left becomes Nothing; a Right becomes a Just.

See also maybeToEither.

> S.eitherToMaybe(S.Left('Cannot divide by zero'))
Nothing

> S.eitherToMaybe(S.Right(42))
Just(42)

Logic

and :: Boolean -⁠> Boolean -⁠> Boolean

Boolean "and".

> S.and(false, false)
false

> S.and(false, true)
false

> S.and(true, false)
false

> S.and(true, true)
true
or :: Boolean -⁠> Boolean -⁠> Boolean

Boolean "or".

> S.or(false, false)
false

> S.or(false, true)
true

> S.or(true, false)
true

> S.or(true, true)
true
not :: Boolean -⁠> Boolean

Boolean "not".

See also complement.

> S.not(false)
true

> S.not(true)
false
complement :: (a -⁠> Boolean) -⁠> a -⁠> Boolean

Takes a unary predicate and a value of any type, and returns the logical negation of applying the predicate to the value.

See also not.

> Number.isInteger(42)
true

> S.complement(Number.isInteger, 42)
false
ifElse :: (a -⁠> Boolean) -⁠> (a -⁠> b) -⁠> (a -⁠> b) -⁠> a -⁠> b

Takes a unary predicate, a unary "if" function, a unary "else" function, and a value of any type, and returns the result of applying the "if" function to the value if the value satisfies the predicate; the result of applying the "else" function to the value otherwise.

See also when and unless.

> S.ifElse(x => x < 0, Math.abs, Math.sqrt, -1)
1

> S.ifElse(x => x < 0, Math.abs, Math.sqrt, 16)
4
when :: (a -⁠> Boolean) -⁠> (a -⁠> a) -⁠> a -⁠> a

Takes a unary predicate, a unary function, and a value of any type, and returns the result of applying the function to the value if the value satisfies the predicate; the value otherwise.

See also unless and ifElse.

> S.when(x => x >= 0, Math.sqrt, 16)
4

> S.when(x => x >= 0, Math.sqrt, -1)
-1
unless :: (a -⁠> Boolean) -⁠> (a -⁠> a) -⁠> a -⁠> a

Takes a unary predicate, a unary function, and a value of any type, and returns the result of applying the function to the value if the value does not satisfy the predicate; the value otherwise.

See also when and ifElse.

> S.unless(x => x < 0, Math.sqrt, 16)
4

> S.unless(x => x < 0, Math.sqrt, -1)
-1
allPass :: Foldable f => f (a -⁠> Boolean) -⁠> a -⁠> Boolean

Takes a structure containing zero or more predicates, and a value of any type. Returns true iff the value satisfies all of the predicates. None of the subsequent predicates will be applied after the first predicate not satisfied.

> S.allPass([S.test(/q/), S.test(/u/), S.test(/i/)], 'quiessence')
true

> S.allPass([S.test(/q/), S.test(/u/), S.test(/i/)], 'fissiparous')
false
anyPass :: Foldable f => f (a -⁠> Boolean) -⁠> a -⁠> Boolean

Takes a structure containing zero or more predicates, and a value of any type. Returns true iff the value satisfies any of the predicates. None of the subsequent predicates will be applied after the first predicate satisfied.

> S.anyPass([S.test(/q/), S.test(/u/), S.test(/i/)], 'incandescent')
true

> S.anyPass([S.test(/q/), S.test(/u/), S.test(/i/)], 'empathy')
false

List

The List type constructor enables type signatures to describe ad hoc polymorphic functions which operate on either Array or String values.

Mental gymnastics are required to treat arrays and strings similarly. [1, 2, 3] is a list containing 1, 2, and 3. 'abc' is a list containing 'a', 'b', and 'c'. But what is the type of 'a'? String, since JavaScript has no Char type! Thus:

'abc' :: String, List String, List (List String), ...

Every member of String is also a member of List String!

slice :: Integer -⁠> Integer -⁠> List a -⁠> Maybe (List a)

Returns Just a list containing the elements from the supplied list from a beginning index (inclusive) to an end index (exclusive). Returns Nothing unless the start interval is less than or equal to the end interval, and the list contains both (half-open) intervals. Accepts negative indices, which indicate an offset from the end of the list.

See also take, drop, takeLast, and dropLast.

> S.slice(1, 3, ['a', 'b', 'c', 'd', 'e'])
Just(['b', 'c'])

> S.slice(-3, -1, ['a', 'b', 'c', 'd', 'e'])
Just(['c', 'd'])

> S.slice(1, 6, ['a', 'b', 'c', 'd', 'e'])
Nothing

> S.slice(2, 6, 'banana')
Just('nana')
at :: Integer -⁠> List 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.

> 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')
head :: List 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.

> S.head([1, 2, 3])
Just(1)

> S.head([])
Nothing
last :: List 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.

> S.last([1, 2, 3])
Just(3)

> S.last([])
Nothing
tail :: List a -⁠> Maybe (List 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.

> S.tail([1, 2, 3])
Just([2, 3])

> S.tail([])
Nothing
init :: List a -⁠> Maybe (List 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.

> S.init([1, 2, 3])
Just([1, 2])

> S.init([])
Nothing
take :: Integer -⁠> List a -⁠> Maybe (List a)

Returns Just the first N elements of the given collection if N is greater than or equal to zero and less than or equal to the length of the collection; Nothing otherwise.

> S.take(2, ['a', 'b', 'c', 'd', 'e'])
Just(['a', 'b'])

> S.take(4, 'abcdefg')
Just('abcd')

> S.take(4, ['a', 'b', 'c'])
Nothing
takeLast :: Integer -⁠> List a -⁠> Maybe (List a)

Returns Just the last N elements of the given collection if N is greater than or equal to zero and less than or equal to the length of the collection; Nothing otherwise.

> S.takeLast(2, ['a', 'b', 'c', 'd', 'e'])
Just(['d', 'e'])

> S.takeLast(4, 'abcdefg')
Just('defg')

> S.takeLast(4, ['a', 'b', 'c'])
Nothing
drop :: Integer -⁠> List a -⁠> Maybe (List a)

Returns Just all but the first N elements of the given collection if N is greater than or equal to zero and less than or equal to the length of the collection; Nothing otherwise.

> S.drop(2, ['a', 'b', 'c', 'd', 'e'])
Just(['c', 'd', 'e'])

> S.drop(4, 'abcdefg')
Just('efg')

> S.drop(4, 'abc')
Nothing
dropLast :: Integer -⁠> List a -⁠> Maybe (List a)

Returns Just all but the last N elements of the given collection if N is greater than or equal to zero and less than or equal to the length of the collection; Nothing otherwise.

> S.dropLast(2, ['a', 'b', 'c', 'd', 'e'])
Just(['a', 'b', 'c'])

> S.dropLast(4, 'abcdefg')
Just('abc')

> S.dropLast(4, 'abc')
Nothing

Array

size :: Foldable f => f a -⁠> Integer

Returns the number of elements of the given structure.

> S.size([])
0

> S.size(['foo', 'bar', 'baz'])
3

> S.size(Nil)
0

> S.size(Cons('foo', Cons('bar', Cons('baz', Nil))))
3

> S.size(S.Nothing)
0

> S.size(S.Just('quux'))
1
append :: (Applicative f, Semigroup (f a)) => a -⁠> f a -⁠> f a

Returns the result of appending the first argument to the second.

See also prepend.

> S.append(3, [1, 2])
[1, 2, 3]

> S.append(3, Cons(1, Cons(2, Nil)))
Cons(1, Cons(2, Cons(3, Nil)))

> S.append([1], S.Nothing)
Just([1])

> S.append([3], S.Just([1, 2]))
Just([1, 2, 3])
prepend :: (Applicative f, Semigroup (f a)) => a -⁠> f a -⁠> f a

Returns the result of prepending the first argument to the second.

See also append.

> S.prepend(1, [2, 3])
[1, 2, 3]

> S.prepend(1, Cons(2, Cons(3, Nil)))
Cons(1, Cons(2, Cons(3, Nil)))

> S.prepend([1], S.Nothing)
Just([1])

> S.prepend([1], S.Just([2, 3]))
Just([1, 2, 3])
joinWith :: String -⁠> Array String -⁠> String

Joins the strings of the second argument separated by the first argument.

Properties:

  • forall s :: String, t :: String. S.joinWith(s, S.splitOn(s, t)) = t

See also splitOn.

> S.joinWith(':', ['foo', 'bar', 'baz'])
'foo:bar:baz'
elem :: (Setoid a, Foldable f) => a -⁠> f a -⁠> Boolean

Takes a value and a structure and returns true iff the value is an element of the structure.

See also find.

> S.elem('c', ['a', 'b', 'c'])
true

> S.elem('x', ['a', 'b', 'c'])
false

> S.elem(3, {x: 1, y: 2, z: 3})
true

> S.elem(8, {x: 1, y: 2, z: 3})
false

> S.elem(0, S.Just(0))
true

> S.elem(0, S.Just(1))
false

> S.elem(0, S.Nothing)
false
find :: Foldable f => (a -⁠> Boolean) -⁠> f a -⁠> Maybe a

Takes a predicate and a structure and returns Just the leftmost element of the structure which satisfies the predicate; Nothing if there is no such element.

See also elem.

> S.find(n => n < 0, [1, -2, 3, -4, 5])
Just(-2)

> S.find(n => n < 0, [1, 2, 3, 4, 5])
Nothing
pluck :: Functor f => String -⁠> f a -⁠> f b

Combines map and prop. pluck(k, xs) is equivalent to map(prop(k), xs).

> S.pluck('x', [{x: 1}, {x: 2}, {x: 3}])
[1, 2, 3]

> S.pluck('x', S.Just({x: 1, y: 2, z: 3}))
Just(1)
unfoldr :: (b -⁠> Maybe (Pair a b)) -⁠> b -⁠> Array a

Takes a function and a seed value, and returns an array generated by applying the function repeatedly. The array is initially empty. The function is initially applied to the seed value. Each application of the function should result in either:

  • Nothing, in which case the array is returned; or

  • Just a pair, in which case the first element is appended to the array and the function is applied to the second element.

> S.unfoldr(n => n < 5 ? S.Just([n, n + 1]) : S.Nothing, 1)
[1, 2, 3, 4]
range :: Integer -⁠> Integer -⁠> Array Integer

Returns an array of consecutive integers starting with the first argument and ending with the second argument minus one. Returns [] if the second argument is less than or equal to the first argument.

> S.range(0, 10)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

> S.range(-5, 0)
[-5, -4, -3, -2, -1]

> S.range(0, -5)
[]
groupBy :: (a -⁠> a -⁠> Boolean) -⁠> Array a -⁠> Array (Array a)

Splits its array argument into an array of arrays of equal, adjacent elements. Equality is determined by the function provided as the first argument. Its behaviour can be surprising for functions that aren't reflexive, transitive, and symmetric (see equivalence relation).

Properties:

  • forall f :: a -> a -> Boolean, xs :: Array a. S.join(S.groupBy(f, xs)) = xs
> S.groupBy(S.equals, [1, 1, 2, 1, 1])
[[1, 1], [2], [1, 1]]

> S.groupBy(x => y => x + y === 0, [2, -3, 3, 3, 3, 4, -4, 4])
[[2], [-3, 3, 3, 3], [4, -4], [4]]
reverse :: (Applicative f, Foldable f, Monoid (f a)) => f a -⁠> f a

Reverses the elements of the given structure.

> S.reverse([1, 2, 3])
[3, 2, 1]

> S.reverse(Cons(1, Cons(2, Cons(3, Nil))))
Cons(3, Cons(2, Cons(1, Nil)))

> S.pipe([S.splitOn(''), S.reverse, S.joinWith('')], 'abc')
'cba'
sort :: (Ord a, Applicative m, Foldable m, Monoid (m a)) => m a -⁠> m a

Performs a stable sort of the elements of the given structure, using Z.lte for comparisons.

Properties:

  • S.sort(S.sort(m)) = S.sort(m) (idempotence)

See also sortBy.

> S.sort(['foo', 'bar', 'baz'])
['bar', 'baz', 'foo']

> S.sort([S.Left(4), S.Right(3), S.Left(2), S.Right(1)])
[Left(2), Left(4), Right(1), Right(3)]
sortBy :: (Ord b, Applicative m, Foldable m, Monoid (m a)) => (a -⁠> b) -⁠> m a -⁠> m a

Performs a stable sort of the elements of the given structure, using Z.lte to compare the values produced by applying the given function to each element of the structure.

Properties:

  • S.sortBy(f, S.sortBy(f, m)) = S.sortBy(f, m) (idempotence)

See also sort.

> S.sortBy(S.prop('rank'), [
.   {rank: 7, suit: 'spades'},
.   {rank: 5, suit: 'hearts'},
.   {rank: 2, suit: 'hearts'},
.   {rank: 5, suit: 'spades'},
. ])
[ {rank: 2, suit: 'hearts'},
. {rank: 5, suit: 'hearts'},
. {rank: 5, suit: 'spades'},
. {rank: 7, suit: 'spades'} ]

> S.sortBy(S.prop('suit'), [
.   {rank: 7, suit: 'spades'},
.   {rank: 5, suit: 'hearts'},
.   {rank: 2, suit: 'hearts'},
.   {rank: 5, suit: 'spades'},
. ])
[ {rank: 5, suit: 'hearts'},
. {rank: 2, suit: 'hearts'},
. {rank: 7, suit: 'spades'},
. {rank: 5, suit: 'spades'} ]

Object

prop :: String -⁠> a -⁠> b

Takes a property name and an object with known properties and returns the value of the specified property. If for some reason the object lacks the specified property, a type error is thrown.

For accessing properties of uncertain objects, use get instead.

See also pluck.

> S.prop('a', {a: 1, b: 2})
1
props :: Array String -⁠> a -⁠> b

Takes a property path (an array of property names) and an object with known structure and returns the value at the given path. If for some reason the path does not exist, a type error is thrown.

For accessing property paths of uncertain objects, use gets instead.

> S.props(['a', 'b', 'c'], {a: {b: {c: 1}}})
1
get :: (Any -⁠> Boolean) -⁠> String -⁠> a -⁠> Maybe b

Takes a predicate, a property name, and an object and returns Just the value of the specified object property if it exists and the value satisfies the given predicate; Nothing otherwise.

See also gets and prop.

> S.get(S.is(Number), 'x', {x: 1, y: 2})
Just(1)

> S.get(S.is(Number), 'x', {x: '1', y: '2'})
Nothing

> S.get(S.is(Number), 'x', {})
Nothing

> S.get($.test([], $.Array($.Number)), 'x', {x: [1, 2, 3]})
Just([1, 2, 3])

> S.get($.test([], $.Array($.Number)), 'x', {x: [1, 2, 3, null]})
Nothing
gets :: (Any -⁠> Boolean) -⁠> Array String -⁠> a -⁠> Maybe b

Takes a predicate, a property path (an array of property names), and an object and returns Just the value at the given path if such a path exists and the value satisfies the given predicate; Nothing otherwise.

See also get.

> S.gets(S.is(Number), ['a', 'b', 'c'], {a: {b: {c: 42}}})
Just(42)

> S.gets(S.is(Number), ['a', 'b', 'c'], {a: {b: {c: '42'}}})
Nothing

> S.gets(S.is(Number), ['a', 'b', 'c'], {})
Nothing

StrMap

StrMap is an abbreviation of string map. A string map is an object, such as {foo: 1, bar: 2, baz: 3}, whose values are all members of the same type. Formally, a value is a member of type StrMap a if its type identifier is 'Object' and the values of its enumerable own properties are all members of type a.

singleton :: String -⁠> a -⁠> StrMap a

Takes a string and a value of any type, and returns a string map with a single entry (mapping the key to the value).

> S.singleton('foo', 42)
{foo: 42}
insert :: String -⁠> a -⁠> StrMap a -⁠> StrMap a

Takes a string, a value of any type, and a string map, and returns a string map comprising all the entries of the given string map plus the entry specified by the first two arguments (which takes precedence).

Equivalent to Haskell's insert function. Similar to Clojure's assoc function.

> S.insert('c', 3, {a: 1, b: 2})
{a: 1, b: 2, c: 3}

> S.insert('a', 4, {a: 1, b: 2})
{a: 4, b: 2}
remove :: String -⁠> StrMap a -⁠> StrMap a

Takes a string and a string map, and returns a string map comprising all the entries of the given string map except the one whose key matches the given string (if such a key exists).

Equivalent to Haskell's delete function. Similar to Clojure's dissoc function.

> S.remove('c', {a: 1, b: 2, c: 3})
{a: 1, b: 2}

> S.remove('c', {})
{}
keys :: StrMap a -⁠> Array String

Returns the keys of the given string map, in arbitrary order.

> S.keys({b: 2, c: 3, a: 1}).sort()
['a', 'b', 'c']
values :: StrMap a -⁠> Array a

Returns the values of the given string map, in arbitrary order.

> S.values({a: 1, c: 3, b: 2}).sort()
[1, 2, 3]
pairs :: StrMap a -⁠> Array (Pair String a)

Returns the key–value pairs of the given string map, in arbitrary order.

> S.pairs({b: 2, a: 1, c: 3}).sort()
[['a', 1], ['b', 2], ['c', 3]]
fromPairs :: Foldable f => f (Pair String a) -⁠> StrMap a

Returns a string map containing the key–value pairs specified by the given Foldable. If a key appears in multiple pairs, the rightmost pair takes precedence.

> S.fromPairs([['a', 1], ['b', 2], ['c', 3]])
{a: 1, b: 2, c: 3}

> S.fromPairs([['x', 1], ['x', 2]])
{x: 2}

Number

negate :: ValidNumber -⁠> ValidNumber

Negates its argument.

> S.negate(12.5)
-12.5

> S.negate(-42)
42
add :: FiniteNumber -⁠> FiniteNumber -⁠> FiniteNumber

Returns the sum of two (finite) numbers.

> S.add(1, 1)
2
sum :: Foldable f => f FiniteNumber -⁠> FiniteNumber

Returns the sum of the given array of (finite) numbers.

> S.sum([1, 2, 3, 4, 5])
15

> S.sum([])
0

> S.sum(S.Just(42))
42

> S.sum(S.Nothing)
0
sub :: FiniteNumber -⁠> (FiniteNumber -⁠> FiniteNumber)

Takes a finite number n and returns the subtract n function.

See also sub_.

> S.map(S.sub(1), [1, 2, 3])
[0, 1, 2]
sub_ :: FiniteNumber -⁠> FiniteNumber -⁠> FiniteNumber

Returns the difference between two (finite) numbers.

See also sub.

> S.sub_(4, 2)
2
mult :: FiniteNumber -⁠> FiniteNumber -⁠> FiniteNumber

Returns the product of two (finite) numbers.

> S.mult(4, 2)
8
product :: Foldable f => f FiniteNumber -⁠> FiniteNumber

Returns the product of the given array of (finite) numbers.

> S.product([1, 2, 3, 4, 5])
120

> S.product([])
1

> S.product(S.Just(42))
42

> S.product(S.Nothing)
1
div :: NonZeroFiniteNumber -⁠> (FiniteNumber -⁠> FiniteNumber)

Takes a non-zero finite number n and returns the divide by n function.

See also div_.

> S.map(S.div(2), [0, 1, 2, 3])
[0, 0.5, 1, 1.5]
div_ :: FiniteNumber -⁠> NonZeroFiniteNumber -⁠> FiniteNumber

Returns the result of dividing its first argument (a finite number) by its second argument (a non-zero finite number).

See also div.

> S.div_(7, 2)
3.5

> S.map(S.div_(24), [1, 2, 3, 4])
[24, 12, 8, 6]
pow :: FiniteNumber -⁠> (FiniteNumber -⁠> FiniteNumber)

Takes a finite number n and returns the power of n function.

See also pow_.

> S.map(S.pow(2), [-3, -2, -1, 0, 1, 2, 3])
[9, 4, 1, 0, 1, 4, 9]

> S.map(S.pow(0.5), [1, 4, 9, 16, 25])
[1, 2, 3, 4, 5]
pow_ :: FiniteNumber -⁠> FiniteNumber -⁠> FiniteNumber

Curried version of Math.pow.

See also pow.

> S.map(S.pow_(10), [-3, -2, -1, 0, 1, 2, 3])
[0.001, 0.01, 0.1, 1, 10, 100, 1000]
mean :: Foldable f => f FiniteNumber -⁠> Maybe FiniteNumber

Returns the mean of the given array of (finite) numbers.

> S.mean([1, 2, 3, 4, 5])
Just(3)

> S.mean([])
Nothing

> S.mean(S.Just(42))
Just(42)

> S.mean(S.Nothing)
Nothing

Integer

even :: Integer -⁠> Boolean

Returns true if the given integer is even; false if it is odd.

> S.even(42)
true

> S.even(99)
false
odd :: Integer -⁠> Boolean

Returns true if the given integer is odd; false if it is even.

> S.odd(99)
true

> S.odd(42)
false

Parse

parseDate :: String -⁠> Maybe ValidDate

Takes a string and returns Just the date represented by the string if it does in fact represent a date; Nothing otherwise.

> S.parseDate('2011-01-19T17:40:00Z')
Just(new Date('2011-01-19T17:40:00.000Z'))

> S.parseDate('today')
Nothing
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.

> S.parseFloat('-123.45')
Just(-123.45)

> S.parseFloat('foo.bar')
Nothing
parseInt :: Radix -⁠> String -⁠> Maybe Integer

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.

This function is stricter than parseInt: a string is considered to represent an integer only if all its non-prefix characters are members of the character set specified by the radix.

> S.parseInt(10, '-42')
Just(-42)

> S.parseInt(16, '0xFF')
Just(255)

> S.parseInt(16, '0xGG')
Nothing
parseJson :: (Any -⁠> Boolean) -⁠> String -⁠> Maybe a

Takes a predicate and a string which may or may not be valid JSON, and returns Just the result of applying JSON.parse to the string if the result satisfies the predicate; Nothing otherwise.

> S.parseJson($.test([], $.Array($.Integer)), '[')
Nothing

> S.parseJson($.test([], $.Array($.Integer)), '["1","2","3"]')
Nothing

> S.parseJson($.test([], $.Array($.Integer)), '[0,1.5,3,4.5]')
Nothing

> S.parseJson($.test([], $.Array($.Integer)), '[1,2,3]')
Just([1, 2, 3])

RegExp

regex :: RegexFlags -⁠> String -⁠> RegExp

Takes a RegexFlags and a pattern, and returns a RegExp.

> S.regex('g', ':\\d+:')
/:\d+:/g
regexEscape :: String -⁠> String

Takes a string which may contain regular expression metacharacters, and returns a string with those metacharacters escaped.

Properties:

  • forall s :: String. S.test(S.regex('', S.regexEscape(s)), s) = true
> S.regexEscape('-=*{XYZ}*=-')
'\\-=\\*\\{XYZ\\}\\*=\\-'
test :: RegExp -⁠> String -⁠> Boolean

Takes a pattern and a string, and returns true iff the pattern matches the string.

> S.test(/^a/, 'abacus')
true

> S.test(/^a/, 'banana')
false
match :: NonGlobalRegExp -⁠> String -⁠> Maybe { match :: String, groups :: Array (Maybe String) }

Takes a pattern and a string, and returns Just a match record if the pattern matches the string; Nothing otherwise.

groups :: Array (Maybe String) acknowledges the existence of optional capturing groups.

Properties:

  • forall p :: Pattern, s :: String. S.head(S.matchAll(S.regex('g', p), s)) = S.match(S.regex('', p), s)

See also matchAll.

> S.match(/(good)?bye/, 'goodbye')
Just({match: 'goodbye', groups: [Just('good')]})

> S.match(/(good)?bye/, 'bye')
Just({match: 'bye', groups: [Nothing]})
matchAll :: GlobalRegExp -⁠> String -⁠> Array { match :: String, groups :: Array (Maybe String) }

Takes a pattern and a string, and returns an array of match records.

groups :: Array (Maybe String) acknowledges the existence of optional capturing groups.

See also match.

> S.matchAll(/@([a-z]+)/g, 'Hello, world!')
[]

> S.matchAll(/@([a-z]+)/g, 'Hello, @foo! Hello, @bar! Hello, @baz!')
[ {match: '@foo', groups: [Just('foo')]},
. {match: '@bar', groups: [Just('bar')]},
. {match: '@baz', groups: [Just('baz')]} ]

String

toUpper :: String -⁠> String

Returns the upper-case equivalent of its argument.

See also toLower.

> S.toUpper('ABC def 123')
'ABC DEF 123'
toLower :: String -⁠> String

Returns the lower-case equivalent of its argument.

See also toUpper.

> S.toLower('ABC def 123')
'abc def 123'
trim :: String -⁠> String

Strips leading and trailing whitespace characters.

> S.trim('\t\t foo bar \n')
'foo bar'
stripPrefix :: String -⁠> String -⁠> Maybe String

Returns Just the portion of the given string (the second argument) left after removing the given prefix (the first argument) if the string starts with the prefix; Nothing otherwise.

See also stripSuffix.

> S.stripPrefix('https://', 'https://sanctuary.js.org')
Just('sanctuary.js.org')

> S.stripPrefix('https://', 'http://sanctuary.js.org')
Nothing
stripSuffix :: String -⁠> String -⁠> Maybe String

Returns Just the portion of the given string (the second argument) left after removing the given suffix (the first argument) if the string ends with the suffix; Nothing otherwise.

See also stripPrefix.

> S.stripSuffix('.md', 'README.md')
Just('README')

> S.stripSuffix('.md', 'README')
Nothing
words :: String -⁠> Array String

Takes a string and returns the array of words the string contains (words are delimited by whitespace characters).

See also unwords.

> S.words(' foo bar baz ')
['foo', 'bar', 'baz']
unwords :: Array String -⁠> String

Takes an array of words and returns the result of joining the words with separating spaces.

See also words.

> S.unwords(['foo', 'bar', 'baz'])
'foo bar baz'
lines :: String -⁠> Array String

Takes a string and returns the array of lines the string contains (lines are delimited by newlines: '\n' or '\r\n' or '\r'). The resulting strings do not contain newlines.

See also unlines.

> S.lines('foo\nbar\nbaz\n')
['foo', 'bar', 'baz']
unlines :: Array String -⁠> String

Takes an array of lines and returns the result of joining the lines after appending a terminating line feed ('\n') to each.

See also lines.

> S.unlines(['foo', 'bar', 'baz'])
'foo\nbar\nbaz\n'
splitOn :: String -⁠> String -⁠> Array String

Returns the substrings of its second argument separated by occurrences of its first argument.

See also joinWith and splitOnRegex.

> S.splitOn('::', 'foo::bar::baz')
['foo', 'bar', 'baz']
splitOnRegex :: GlobalRegExp -⁠> String -⁠> Array String

Takes a pattern and a string, and returns the result of splitting the string at every non-overlapping occurrence of the pattern.

Properties:

  • forall s :: String, t :: String. S.joinWith(s, S.splitOnRegex(S.regex('g', S.regexEscape(s)), t)) = t

See also splitOn.

> S.splitOnRegex(/[,;][ ]*/g, 'foo, bar, baz')
['foo', 'bar', 'baz']

> S.splitOnRegex(/[,;][ ]*/g, 'foo;bar;baz')
['foo', 'bar', 'baz']

FAQs

Package last updated on 23 Dec 2017

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc