diff --git a/README.md b/README.md
index d4bad3e5..9130975b 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
# Sanctuary
-Sanctuary is a small functional programming library inspired by Haskell
-and PureScript. It depends on and works nicely with [Ramda][]. Sanctuary
+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:
@@ -49,11 +49,81 @@ _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`._
+### Accessible pseudotype
+
+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.
+
+### Integer pseudotype
+
+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.
+
+### List pseudotype
+
+The List pseudotype represents non-Function values with numeric `length`
+properties greater than or equal to zero, such as `[1, 2, 3]` and `'foo'`.
+
+### 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`](#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.
+
## API
+### Classify
+
+
+
+Takes a [type representative](#type-representatives) and a value of
+any type and returns `true` if the given value is of the specified
+type (either directly or via the prototype chain); `false` otherwise.
+
+Boolean, number, string, and symbol [primitives][] are promoted to
+their object equivalents. `42`, for example, is considered a Number
+and an Object (whereas [`R.is`][R.is] considers it a Number but not
+an Object).
+
+```javascript
+> S.is(Number, 42)
+true
+
+> S.is(Object, 42)
+true
+
+> S.is(String, 42)
+false
+```
+
### Combinator
-
+
+
+The I combinator. Returns its argument. Equivalent to Haskell's `id`
+function.
+
+```javascript
+> S.I('foo')
+"foo"
+```
+
+
The K combinator. Takes two values and returns the first. Equivalent to
Haskell's `const` function.
@@ -61,20 +131,83 @@ Haskell's `const` function.
```javascript
> S.K('foo', 'bar')
"foo"
+
> R.map(S.K(42), R.range(0, 5))
[42, 42, 42, 42, 42]
```
+### Composition
+
+
+
+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`](#pipe).
+
+```javascript
+> S.compose(Math.sqrt, R.inc)(99)
+10
+```
+
+
+
+Takes 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`](#meld).
+
+```javascript
+> S.pipe([R.inc, Math.sqrt, R.dec])(99)
+9
+```
+
+
+
+Takes 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`](#pipe).
+
+```javascript
+> S.meld([Math.pow, R.subtract])(3, 4, 5)
+76
+
+> S.meld([Math.pow, R.subtract])(3)(4)(5)
+76
+```
+
### Maybe type
-
+
The Maybe type represents optional values: a value of type `Maybe a` is
either a Just whose value is of type `a` or a Nothing (with no value).
-The Maybe type satisfies the [Monoid][] and [Monad][] specifications.
+The Maybe type satisfies the [Monoid][], [Monad][], [Foldable][], and
+[Extend][] specifications.
-
+
Returns a Nothing.
@@ -83,7 +216,7 @@ Returns a Nothing.
Nothing()
```
-
+
Takes a value of any type and returns a Just with the given value.
@@ -92,7 +225,7 @@ Takes a value of any type and returns a Just with the given value.
Just(42)
```
-
+
Takes a value of type `Maybe a` and returns a Nothing unless `this`
is a Just *and* the argument is a Just, in which case it returns a
@@ -110,7 +243,7 @@ Nothing()
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.
@@ -126,7 +259,7 @@ Nothing()
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`
@@ -155,7 +288,7 @@ Just([1, 2, 3])
Just([1, 2, 3])
```
-
+
Returns a Nothing.
@@ -164,7 +297,7 @@ Returns a Nothing.
Nothing()
```
-
+
Takes a value of any type and returns `true` if:
@@ -190,7 +323,21 @@ false
false
```
-
+
+
+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`.
+
+```javascript
+> S.Nothing().extend(function(x) { return x.value + 1; })
+Nothing()
+
+> S.Just(42).extend(function(x) { return x.value + 1; })
+Just(43)
+```
+
+
Takes a predicate and returns `this` if `this` is a Just whose value
satisfies the predicate; Nothing otherwise.
@@ -203,7 +350,7 @@ Just(42)
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
@@ -213,11 +360,11 @@ this Just's value.
> S.Nothing().map(R.inc)
Nothing()
-> S.Just(42).map(R.inc)
-Just(43)
+> S.Just([1, 2, 3]).map(R.sum)
+Just(6)
```
-
+
Takes a value of any type and returns a Just with the given value.
@@ -226,7 +373,24 @@ Takes a value of any type and returns a Just with the given value.
Just(42)
```
-
+
+
+Takes a function and an initial value of any type, and returns:
+
+ - the initial value if `this` is a Nothing; otherwise
+
+ - the result of applying the function to the initial value and this
+ Just's value.
+
+```javascript
+> S.Nothing().reduce(R.add, 10)
+10
+
+> S.Just(5).reduce(R.add, 10)
+15
+```
+
+
Returns `false` if `this` is a Nothing; `true` if `this` is a Just.
@@ -238,7 +402,7 @@ false
true
```
-
+
Returns the string representation of the Maybe.
@@ -250,12 +414,12 @@ Returns the string representation of the Maybe.
"Just([1, 2, 3])"
```
-
+
A reference to the Maybe type. Useful for determining whether two
values such as `S.Nothing()` and `S.Just(42)` are of the same type.
-
+
Returns a Nothing. Though this is a constructor function the `new`
keyword needn't be used.
@@ -265,7 +429,7 @@ keyword needn't be used.
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
@@ -276,7 +440,7 @@ used.
Just(42)
```
-
+
Takes a default value and a Maybe, and returns the Maybe's value
if the Maybe is a Just; the default value otherwise.
@@ -289,7 +453,7 @@ if the Maybe is a Just; the default value otherwise.
0
```
-
+
Takes a value and returns Nothing if the value is null or undefined;
Just the value otherwise.
@@ -302,13 +466,53 @@ Nothing()
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.
+
+```javascript
+> S.maybe(0, R.length, S.Just('refuge'))
+6
+
+> S.maybe(0, R.length, S.Nothing())
+0
+```
+
+
+
+Takes a list of Maybes and returns a list containing each Just's value.
+
+```javascript
+> 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.
+
+```javascript
+> S.mapMaybe(S.head, [[], [1, 2, 3], [], [4, 5, 6], []])
+[1, 4]
+```
+
+
Takes a function `f` which may throw and returns a curried function
`g` which will not throw. The result of applying `g` is determined by
applying `f` to the same arguments: if this succeeds, `g` returns Just
the result; otherwise `g` returns Nothing.
+See also [`encaseEither`](#encaseEither).
+
```javascript
> S.encase(eval)('1 + 1')
Just(2)
@@ -319,15 +523,16 @@ Nothing()
### Either type
-
+
The Either type represents values with two possibilities: a value of type
`Either a b` is either a Left whose value is of type `a` or a Right whose
value is of type `b`.
-The Either type satisfies the [Semigroup][] and [Monad][] specifications.
+The Either type satisfies the [Semigroup][], [Monad][], and [Extend][]
+specifications.
-
+
Takes a value of any type and returns a Right with the given value.
@@ -336,7 +541,7 @@ Takes a value of any type and returns a Right with the given value.
Right(42)
```
-
+
Takes a value of type `Either a b` and returns a Left unless `this`
is a Right *and* the argument is a Right, in which case it returns
@@ -354,7 +559,7 @@ Left("Cannot divide by zero")
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.
@@ -373,7 +578,7 @@ Left("Cannot represent square root of negative number")
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`
@@ -403,7 +608,7 @@ Right([1, 2, 3])
Right([1, 2, 3])
```
-
+
Takes a value of any type and returns `true` if:
@@ -424,7 +629,21 @@ false
false
```
-
+
+
+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`.
+
+```javascript
+> S.Left('Cannot divide by zero').extend(function(x) { return x.value + 1; })
+Left("Cannot divide by zero")
+
+> S.Right(42).extend(function(x) { return 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
@@ -434,11 +653,11 @@ this Right's value.
> S.Left('Cannot divide by zero').map(R.inc)
Left("Cannot divide by zero")
-> S.Right(42).map(R.inc)
-Right(43)
+> S.Right([1, 2, 3]).map(R.sum)
+Right(6)
```
-
+
Takes a value of any type and returns a Right with the given value.
@@ -447,7 +666,7 @@ Takes a value of any type and returns a Right with the given value.
Right(42)
```
-
+
Returns `false` if `this` is a Left; `true` if `this` is a Right.
@@ -459,7 +678,7 @@ false
true
```
-
+
Returns the string representation of the Either.
@@ -471,13 +690,13 @@ Returns the string representation of the Either.
"Right([1, 2, 3])"
```
-
+
A reference to the Either type. Useful for determining whether two
values such as `S.Left('Cannot divide by zero')` and `S.Right(42)`
are of the same type.
-
+
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
@@ -488,7 +707,7 @@ used.
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
@@ -499,7 +718,7 @@ used.
Right(42)
```
-
+
Takes two functions and an Either, and returns the result of
applying the first function to the Left's value, if the Either
@@ -514,9 +733,47 @@ Right's value, if the Either is a Right.
"42"
```
+
+
+Takes two functions, `f` and `g`, the second of which may throw,
+and returns a curried function of the same arity as `g` which will
+not throw. The result of applying this function is determined by
+applying `g` to the same arguments: if this succeeds, the return
+value is a Right whose value is the result; otherwise the return
+value is a Left whose value is the result of applying `f` to the
+caught Error object.
+
+See also [`encase`](#encase).
+
+```javascript
+> S.encaseEither(R.identity, Array)(0)
+Right([])
+
+> S.encaseEither(R.identity, Array)(-1)
+Left(RangeError: Invalid array length)
+
+> S.encaseEither(R.prop('message'), Array)(-1)
+Left("Invalid array length")
+```
+
+
+
+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.
+
+```javascript
+> S.maybeToEither('Expecting an integer', S.parseInt(10, 'xyz'))
+Left("Expecting an integer")
+
+> S.maybeToEither('Expecting an integer', S.parseInt(10, '42'))
+Right(42)
+```
+
### Control
-
+
Takes two values of the same type and returns the second value
if the first is "true"; the first value otherwise. An array is
@@ -532,7 +789,7 @@ Just(2)
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"
@@ -547,7 +804,7 @@ Just(1)
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
@@ -566,7 +823,7 @@ Nothing()
### List
-
+
Returns Just a list containing the elements from the supplied list
from a beginning index (inclusive) to an end index (exclusive).
@@ -595,7 +852,7 @@ Nothing()
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.
@@ -612,7 +869,7 @@ Nothing()
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.
@@ -625,7 +882,7 @@ Just(1)
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.
@@ -638,7 +895,7 @@ Just(3)
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;
@@ -652,7 +909,7 @@ Just([2, 3])
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;
@@ -666,7 +923,7 @@ Just([1, 2])
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
@@ -684,7 +941,25 @@ Just("abcd")
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.
+
+```javascript
+> 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
@@ -702,7 +977,25 @@ Just("efg")
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.
+
+```javascript
+> 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
@@ -716,14 +1009,14 @@ Just(-2)
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 Number` is an alternative
+As a result, `String -> String -> Maybe Integer` is an alternative
type signature.
```javascript
@@ -740,14 +1033,14 @@ Just(1)
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 Number` is an alternative
+As a result, `String -> String -> Maybe Integer` is an alternative
type signature.
```javascript
@@ -764,53 +1057,69 @@ Just(3)
Nothing()
```
-
+
-Takes a list of objects and plucks the value of the specified key
-for each object in the list. Returns the value wrapped in a Just
-if an object has the key and a Nothing if it does not.
+Takes a [type representative](#type-representatives), 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`](#is)); Nothing otherwise.
-```javascript
-> S.pluck('a', [{a: 1, b: 2}, {a: 4, b: 5}, {b: 3, c: 7}])
-[Just(1), Just(4), Nothing()]
+See also [`get`](#get).
-> S.pluck('x', [{x: 1}, {x: 2}, {x: undefined}])
-[Just(1), Just(2), Just(undefined)]
+```javascript
+> S.pluck(Number, 'x', [{x: 1}, {x: 2}, {x: '3'}, {x: null}, {}])
+[Just(1), Just(2), Nothing(), Nothing(), Nothing()]
```
### Object
-
+
-Takes a property name and an object and returns Just the value of
-the specified property of the object if the object has such an own
-property; Nothing otherwise.
+Takes a [type representative](#type-representatives), 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`](#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`](#gets).
```javascript
-> S.get('x', {x: 1, y: 2})
+> S.get(Number, 'x', {x: 1, y: 2})
Just(1)
-> S.get('toString', {x: 1, y: 2})
+> S.get(Number, 'x', {x: '1', y: '2'})
+Nothing()
+
+> S.get(Number, 'x', {})
Nothing()
```
-
+
+
+Takes a [type representative](#type-representatives), 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.
-Takes a list of property names and an object and returns Just the
-value at the path specified by the list of property names if such
-a path exists; Nothing otherwise.
+See also [`get`](#get).
```javascript
-> S.gets(['a', 'b', 'c'], {a: {b: {c: 42}}})
+> S.gets(Number, ['a', 'b', 'c'], {a: {b: {c: 42}}})
Just(42)
-> S.gets(['a', 'b', 'c'], {})
+> S.gets(Number, ['a', 'b', 'c'], {a: {b: {c: '42'}}})
+Nothing()
+
+> S.gets(Number, ['a', 'b', 'c'], {})
Nothing()
```
### Parse
-
+
Takes a string and returns Just the date represented by the string
if it does in fact represent a date; Nothing otherwise.
@@ -823,7 +1132,7 @@ Just(new Date("2011-01-19T17:40:00.000Z"))
Nothing()
```
-
+
Takes a string and returns Just the number represented by the string
if it does in fact represent a number; Nothing otherwise.
@@ -836,7 +1145,7 @@ Just(-123.45)
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
@@ -858,7 +1167,7 @@ Just(255)
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
@@ -874,7 +1183,7 @@ Nothing()
### RegExp
-
+
Takes a pattern and a string, and returns Just a list of matches
if the pattern matches the string; Nothing otherwise. Each match
@@ -889,10 +1198,65 @@ Just([Just("goodbye"), Just("good")])
Just([Just("bye"), Nothing()])
```
+### String
+
+
+
+Takes a string and returns the list of words the string contains
+(words are delimited by whitespace characters).
+
+See also [`unwords`](#unwords).
+
+```javascript
+> 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`](#words).
+
+```javascript
+> 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`](#unlines).
+
+```javascript
+> 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`](#lines).
+
+```javascript
+> S.unlines(['foo', 'bar', 'baz'])
+"foo\nbar\nbaz\n"
+```
+
+[Extend]: https://github.com/fantasyland/fantasy-land#extend
+[Foldable]: https://github.com/fantasyland/fantasy-land#foldable
[Monad]: https://github.com/fantasyland/fantasy-land#monad
[Monoid]: https://github.com/fantasyland/fantasy-land#monoid
[R.equals]: http://ramdajs.com/docs/#equals
+[R.is]: http://ramdajs.com/docs/#is
[R.map]: http://ramdajs.com/docs/#map
[Ramda]: http://ramdajs.com/
[Semigroup]: https://github.com/fantasyland/fantasy-land#semigroup
[parseInt]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseInt
+[primitives]: https://developer.mozilla.org/en-US/docs/Glossary/Primitive
diff --git a/bower.json b/bower.json
index bfc314c7..8beb7c99 100644
--- a/bower.json
+++ b/bower.json
@@ -1,6 +1,6 @@
{
"name": "sanctuary",
- "version": "0.6.0",
+ "version": "0.7.0",
"description": "Refuge from unsafe JavaScript",
"license": "MIT",
"repository": {
diff --git a/package.json b/package.json
index 54644801..1843f5e4 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "sanctuary",
- "version": "0.6.0",
+ "version": "0.7.0",
"description": "Refuge from unsafe JavaScript",
"license": "MIT",
"repository": {