Sanctuary is a 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))
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 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.
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
(=>).
What is the type of values which support property access? In other words,
what is the type of which every value except null and undefined is a
member? Object is close, but Object.create(null) produces a value which
supports property access but which is not a member of the Object type.
Sanctuary uses the Accessible pseudotype to represent the set of values which support property access.
The Integer pseudotype represents integers in the range (-2^53 .. 2^53). It is a pseudotype because each Integer is represented by a Number value. Sanctuary's run-time type checking asserts that a valid Number value is provided wherever an Integer value is required.
The List pseudotype represents non-Function values with numeric length
properties greater than or equal to zero, such as [1, 2, 3] and 'foo'.
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.
Takes a value, x, of any type and returns its type identifier. If
x has a '@@type' property whose value is a string, x['@@type']
is the type identifier. Otherwise, the type identifier is the result
of applying R.type to x.
'@@type' properties should use the form '<package-name>/<type-name>',
where <package-name> is the name of the npm package in which the type
is defined.
> S.type(S.Just(42))
'sanctuary/Maybe'
> S.type([1, 2, 3])
'Array'Takes a type representative and a value of
any type and returns true if the given value is of the specified
type; false otherwise. Subtyping is not respected.
> S.is(Number, 42)
true
> S.is(Object, 42)
false
> S.is(String, 42)
falseThe I combinator. Returns its argument. Equivalent to Haskell's id
function.
> S.I('foo')
'foo'The K combinator. Takes two values and returns the first. Equivalent to
Haskell's const function.
> S.K('foo', 'bar')
'foo'
> R.map(S.K(42), R.range(0, 5))
[42, 42, 42, 42, 42]Takes a binary function and two values and returns the result of
applying the function - with its argument order reversed - to the
values. flip may also be applied to a Ramda-style curried
function with arity greater than two.
> R.map(S.flip(Math.pow)(2), [1, 2, 3, 4, 5])
[1, 4, 9, 16, 25]Promotes a unary function to a function which operates on a Functor.
> S.lift(R.inc, S.Just(2))
S.Just(3)
> S.lift(R.inc, S.Nothing())
S.Nothing()Promotes a binary function to a function which operates on two Applys.
> S.lift2(R.add, S.Just(2), S.Just(3))
S.Just(5)
> S.lift2(R.add, S.Just(2), S.Nothing())
S.Nothing()
> S.lift2(S.and, S.Just(true), S.Just(true))
S.Just(true)
> S.lift2(S.and, S.Just(true), S.Just(false))
S.Just(false)Promotes a ternary function to a function which operates on three Applys.
> S.lift3(R.reduce, S.Just(R.add), S.Just(0), S.Just([1, 2, 3]))
S.Just(6)
> S.lift3(R.reduce, S.Just(R.add), S.Just(0), S.Nothing())
S.Nothing()Takes two functions assumed to be unary and a value of any type, and returns the result of applying the first function to the result of applying the second function to the given value.
In general terms, compose performs right-to-left composition of two
unary functions.
See also pipe.
> S.compose(Math.sqrt, R.inc)(99)
10Takes a list 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 a list
of functions. pipe([f, g, h], x) is equivalent to h(g(f(x))).
See also meld.
> S.pipe([R.inc, Math.sqrt, R.dec])(99)
9Takes a list of non-nullary functions and returns a curried function whose arity is one greater than the sum of the arities of the given functions less the number of functions.
The behaviour of meld is best conveyed diagrammatically. The following
diagram depicts the "melding" of binary functions f and g:
+-------+
--- a --->| |
| f | +-------+
--- b --->| |--- f(a, b) --->| |
+-------+ | g |
--- c ---------------------------->| |--- g(f(a, b), c) --->
+-------+
See also pipe.
> S.meld([Math.pow, R.subtract])(3, 4, 5)
76
> S.meld([Math.pow, R.subtract])(3)(4)(5)
76The 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, Monad, Foldable, and Extend specifications.
Returns a Nothing.
> S.Maybe.empty()
Nothing()Takes a value of any type and returns a Just with the given value.
> S.Maybe.of(42)
Just(42)Maybe type identifier, 'sanctuary/Maybe'.
true if this is a Nothing; false if this is a Just.
> S.Nothing().isNothing
true
> S.Just(42).isNothing
falsetrue if this is a Just; false if this is a Nothing.
> S.Just(42).isJust
true
> S.Nothing().isJust
falseTakes 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.
> 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)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.
> S.Nothing().chain(S.parseFloat)
Nothing()
> S.Just('xxx').chain(S.parseFloat)
Nothing()
> S.Just('12.34').chain(S.parseFloat)
Just(12.34)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.
> 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])Returns a Nothing.
> S.Just(42).empty()
Nothing()Takes a value of any type and returns true if:
-
it is a Nothing and
thisis a Nothing; or -
it is a Just and
thisis a Just, and their values are equal according toR.equals.
> S.Nothing().equals(S.Nothing())
true
> S.Nothing().equals(null)
false
> S.Just([1, 2, 3]).equals(S.Just([1, 2, 3]))
true
> S.Just([1, 2, 3]).equals(S.Just([3, 2, 1]))
false
> S.Just([1, 2, 3]).equals(S.Nothing())
falseTakes 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.
> S.Nothing().extend(x => x.value + 1)
Nothing()
> S.Just(42).extend(x => x.value + 1)
Just(43)Takes a predicate and returns this if this is a Just whose value
satisfies the predicate; Nothing otherwise.
> S.Just(42).filter(n => n % 2 === 0)
Just(42)
> S.Just(43).filter(n => n % 2 === 0)
Nothing()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.
> S.Nothing().map(R.inc)
Nothing()
> S.Just([1, 2, 3]).map(R.sum)
Just(6)Takes a value of any type and returns a Just with the given value.
> S.Nothing().of(42)
Just(42)Takes a function and an initial value of any type, and returns:
-
the initial value if
thisis a Nothing; otherwise -
the result of applying the function to the initial value and this Just's value.
> S.Nothing().reduce(R.add, 10)
10
> S.Just(5).reduce(R.add, 10)
15Returns false if this is a Nothing; true if this is a Just.
> S.Nothing().toBoolean()
false
> S.Just(42).toBoolean()
trueReturns the string representation of the Maybe.
> S.Nothing().toString()
'Nothing()'
> S.Just([1, 2, 3]).toString()
'Just([1, 2, 3])'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])'Returns a Nothing. Though this is a constructor function the new
keyword needn't be used.
> S.Nothing()
Nothing()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.
> S.Just(42)
Just(42)Returns true if the given Maybe is a Nothing; false if it is a Just.
> S.isNothing(S.Nothing())
true
> S.isNothing(S.Just(42))
falseReturns true if the given Maybe is a Just; false if it is a Nothing.
> S.isJust(S.Just(42))
true
> S.isJust(S.Nothing())
falseTakes a default value and a Maybe, and returns the Maybe's value if the Maybe is a Just; the default value otherwise.
> S.fromMaybe(0, S.Just(42))
42
> S.fromMaybe(0, S.Nothing())
0Takes 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)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.
> S.maybe(0, R.length, S.Just('refuge'))
6
> S.maybe(0, R.length, S.Nothing())
0Takes a list of Maybes and returns a list containing each Just's value.
> S.catMaybes([S.Just('foo'), S.Nothing(), S.Just('baz')])
['foo', 'baz']Takes a function and a list, applies the function to each element of the list, and returns a list of "successful" results. If the result of applying the function to an element of the list is a Nothing, the result is discarded; if the result is a Just, the Just's value is included in the output list.
In general terms, mapMaybe filters a list while mapping over it.
> S.mapMaybe(S.head, [[], [1, 2, 3], [], [4, 5, 6], []])
[1, 4]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 a 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()Binary version of encase.
Ternary version of encase.
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, Monad, and Extend specifications.
Takes a value of any type and returns a Right with the given value.
> S.Either.of(42)
Right(42)Either type identifier, 'sanctuary/Either'.
true if this is a Left; false if this is a Right.
> S.Left('Cannot divide by zero').isLeft
true
> S.Right(42).isLeft
falsetrue if this is a Right; false if this is a Left.
> S.Right(42).isRight
true
> S.Left('Cannot divide by zero').isRight
falseTakes 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.
> 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)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.
> global.sqrt = n =>
. n < 0 ? S.Left('Cannot represent square root of negative number')
. : S.Right(Math.sqrt(n))
sqrt
> 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)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.
> 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])Takes a value of any type and returns true if:
-
it is a Left and
thisis a Left, and their values are equal according toR.equals; or -
it is a Right and
thisis a Right, and their values are equal according toR.equals.
> S.Right([1, 2, 3]).equals(S.Right([1, 2, 3]))
true
> S.Right([1, 2, 3]).equals(S.Left([1, 2, 3]))
false
> S.Right(42).equals(42)
falseTakes 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.
> S.Left('Cannot divide by zero').extend(x => x.value + 1)
Left('Cannot divide by zero')
> S.Right(42).extend(x => x.value + 1)
Right(43)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.
> S.Left('Cannot divide by zero').map(R.inc)
Left('Cannot divide by zero')
> S.Right([1, 2, 3]).map(R.sum)
Right(6)Takes a value of any type and returns a Right with the given value.
> S.Left('Cannot divide by zero').of(42)
Right(42)Returns false if this is a Left; true if this is a Right.
> S.Left(42).toBoolean()
false
> S.Right(42).toBoolean()
trueReturns the string representation of the Either.
> S.Left('Cannot divide by zero').toString()
'Left("Cannot divide by zero")'
> S.Right([1, 2, 3]).toString()
'Right([1, 2, 3])'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])'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.
> S.Left('Cannot divide by zero')
Left('Cannot divide by zero')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.
> S.Right(42)
Right(42)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))
falseReturns 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'))
falseTakes 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(R.toUpper, R.toString, S.Left('Cannot divide by zero'))
'CANNOT DIVIDE BY ZERO'
> S.either(R.toUpper, R.toString, S.Right(42))
'42'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 input'))
> S.encaseEither(R.prop('message'), JSON.parse, '[')
Left('Unexpected end of input')Binary version of encaseEither.
Ternary version of encaseEither.
Takes a value of any type and a Maybe, and returns an Either. If the second argument is a Nothing, a Left containing the first argument is returned. If the second argument is a Just, a Right containing the Just's value is returned.
> S.maybeToEither('Expecting an integer', S.parseInt(10, 'xyz'))
Left('Expecting an integer')
> S.maybeToEither('Expecting an integer', S.parseInt(10, '42'))
Right(42)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.
> S.and(S.Just(1), S.Just(2))
Just(2)
> S.and(S.Nothing(), S.Just(3))
Nothing()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.
> S.or(S.Just(1), S.Just(2))
Just(1)
> S.or(S.Nothing(), S.Just(3))
Just(3)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.
> S.xor(S.Nothing(), S.Just(1))
Just(1)
> S.xor(S.Just(2), S.Just(3))
Nothing()Takes a Boolean and returns the negation of that value
(false for true; true for false).
> S.not(true)
false
> S.not(false)
trueTakes 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.
> S.ifElse(x => x < 0, Math.abs, Math.sqrt, -1)
1
> S.ifElse(x => x < 0, Math.abs, Math.sqrt, 16)
4Takes an array of unary predicates and a value of any type
and returns true if all the predicates pass; false otherwise.
None of the subsequent predicates will be evaluated after the
first failed predicate.
> 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')
falseTakes an array of unary predicates and a value of any type
and returns true if any of the predicates pass; false otherwise.
None of the subsequent predicates will be evaluated after the
first passed predicate.
> 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')
falseReturns 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.
Dispatches to its third argument's slice method if present. As a
result, one may replace [a] with String in the type signature.
> S.slice(1, 3, ['a', 'b', 'c', 'd', 'e'])
Just(['b', 'c'])
> S.slice(-2, -0, ['a', 'b', 'c', 'd', 'e'])
Just(['d', 'e'])
> S.slice(2, -0, ['a', 'b', 'c', 'd', 'e'])
Just(['c', 'd', 'e'])
> S.slice(1, 6, ['a', 'b', 'c', 'd', 'e'])
Nothing()
> S.slice(2, 6, 'banana')
Just('nana')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')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()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()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()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()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. Supports Array, String, and
any other collection type which provides a slice method.
> S.take(2, ['a', 'b', 'c', 'd', 'e'])
Just(['a', 'b'])
> S.take(4, 'abcdefg')
Just('abcd')
> S.take(4, ['a', 'b', 'c'])
Nothing()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. Supports Array, String, and
any other collection type which provides a slice method.
> S.takeLast(2, ['a', 'b', 'c', 'd', 'e'])
Just(['d', 'e'])
> S.takeLast(4, 'abcdefg')
Just('defg')
> S.takeLast(4, ['a', 'b', 'c'])
Nothing()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. Supports Array, String,
and any other collection type which provides a slice method.
> S.drop(2, ['a', 'b', 'c', 'd', 'e'])
Just(['c', 'd', 'e'])
> S.drop(4, 'abcdefg')
Just('efg')
> S.drop(4, 'abc')
Nothing()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. Supports Array, String,
and any other collection type which provides a slice method.
> S.dropLast(2, ['a', 'b', 'c', 'd', 'e'])
Just(['a', 'b', 'c'])
> S.dropLast(4, 'abcdefg')
Just('abc')
> S.dropLast(4, 'abc')
Nothing()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.
> S.find(n => n < 0, [1, -2, 3, -4, 5])
Just(-2)
> S.find(n => n < 0, [1, 2, 3, 4, 5])
Nothing()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.
Dispatches to its second argument's indexOf method if present.
As a result, String -> String -> Maybe Integer is an alternative
type signature.
> S.indexOf('a', ['b', 'a', 'n', 'a', 'n', 'a'])
Just(1)
> S.indexOf('x', ['b', 'a', 'n', 'a', 'n', 'a'])
Nothing()
> S.indexOf('an', 'banana')
Just(1)
> S.indexOf('ax', 'banana')
Nothing()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.
Dispatches to its second argument's lastIndexOf method if present.
As a result, String -> String -> Maybe Integer is an alternative
type signature.
> S.lastIndexOf('a', ['b', 'a', 'n', 'a', 'n', 'a'])
Just(5)
> S.lastIndexOf('x', ['b', 'a', 'n', 'a', 'n', 'a'])
Nothing()
> S.lastIndexOf('an', 'banana')
Just(3)
> S.lastIndexOf('ax', 'banana')
Nothing()Takes a type representative, a property name,
and a list of objects and returns a list of equal length. Each element
of the output list is Just the value of the specified property of the
corresponding object if the value is of the specified type (according
to is); Nothing otherwise.
See also get.
> S.pluck(Number, 'x', [{x: 1}, {x: 2}, {x: '3'}, {x: null}, {}])
[Just(1), Just(2), Nothing(), Nothing(), Nothing()]Takes a function and a seed value, and returns a list generated by applying the function repeatedly. The list is initially empty. The function is initially applied to the seed value. Each application of the function should result in either:
-
a Nothing, in which case the list is returned; or
-
Just a pair, in which case the first element is appended to the list 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]Takes a type representative, a property
name, and an object and returns Just the value of the specified object
property if it is of the specified type (according to is);
Nothing otherwise.
The Object type representative may be used as a catch-all since most
values have Object.prototype in their prototype chains.
See also gets.
> S.get(Number, 'x', {x: 1, y: 2})
Just(1)
> S.get(Number, 'x', {x: '1', y: '2'})
Nothing()
> S.get(Number, 'x', {})
Nothing()Takes a type representative, 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 and the value is of the specified type; Nothing otherwise.
See also get.
> S.gets(Number, ['a', 'b', 'c'], {a: {b: {c: 42}}})
Just(42)
> S.gets(Number, ['a', 'b', 'c'], {a: {b: {c: '42'}}})
Nothing()
> S.gets(Number, ['a', 'b', 'c'], {})
Nothing()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()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()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()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.
> S.parseJson('["foo","bar","baz"]')
Just(['foo', 'bar', 'baz'])
> S.parseJson('[')
Nothing()Takes a RegexFlags and a pattern, and returns a RegExp.
> S.regex('g', ':\\d+:')
/:\d+:/gTakes 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\\}\\*=\\-'Takes a pattern and a string, and returns true if the pattern
matches the string; false otherwise.
> S.test(/^a/, 'abacus')
true
> S.test(/^a/, 'banana')
falseTakes 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.
> S.match(/(good)?bye/, 'goodbye')
Just([Just('goodbye'), Just('good')])
> S.match(/(good)?bye/, 'bye')
Just([Just('bye'), Nothing()])Takes a string and returns the list of words the string contains (words are delimited by whitespace characters).
See also unwords.
> S.words(' foo bar baz ')
['foo', 'bar', 'baz']Takes a list of words and returns the result of joining the words with separating spaces.
See also words.
> S.unwords(['foo', 'bar', 'baz'])
'foo bar baz'Takes a string and returns the list 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']Takes a list 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'