From ef4f1d1e3778c797545597d509dfe3d4400f7d20 Mon Sep 17 00:00:00 2001 From: David Chambers Date: Sat, 26 May 2018 18:39:38 +0200 Subject: [PATCH] Version 1.0.0 --- README.md | 316 +++++++++++++++++++++++++++++++++++++++++++++++++++ package.json | 2 +- 2 files changed, 317 insertions(+), 1 deletion(-) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..f2c19ba --- /dev/null +++ b/README.md @@ -0,0 +1,316 @@ +Fantasy Land + +# sanctuary-either + +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`. + +`Either a b` satisfies the following [Fantasy Land][] specifications: + +```javascript +> const Useless = require ('sanctuary-useless') + +> S.map (k => k + ' '.repeat (16 - k.length) + +. (Z[k].test (Right (Useless)) ? '\u2705 ' : +. Z[k].test (Right (['foo'])) ? '\u2705 * ' : +. /* otherwise */ '\u274C ')) +. (S.keys (Z.filter ($.test ([]) ($.TypeClass), Z))) +[ 'Setoid ✅ * ', // if ‘a’ and ‘b’ satisfy Setoid +. 'Ord ✅ * ', // if ‘a’ and ‘b’ satisfy Ord +. 'Semigroupoid ❌ ', +. 'Category ❌ ', +. 'Semigroup ✅ * ', // if ‘a’ and ‘b’ satisfy Semigroup +. 'Monoid ❌ ', +. 'Group ❌ ', +. 'Filterable ❌ ', +. 'Functor ✅ ', +. 'Bifunctor ✅ ', +. 'Profunctor ❌ ', +. 'Apply ✅ ', +. 'Applicative ✅ ', +. 'Chain ✅ ', +. 'ChainRec ✅ ', +. 'Monad ✅ ', +. 'Alt ✅ ', +. 'Plus ❌ ', +. 'Alternative ❌ ', +. 'Foldable ✅ ', +. 'Traversable ✅ ', +. 'Extend ✅ ', +. 'Comonad ❌ ', +. 'Contravariant ❌ ' ] +``` + +#### `Either :: TypeRep Either` + +Either [type representative][]. + +#### `Either.Left :: a -⁠> Either a b` + +Constructs a value of type `Either a b` from a value of type `a`. + +```javascript +> Left ('sqrt undefined for -1') +Left ('sqrt undefined for -1') +``` + +#### `Either.Right :: b -⁠> Either a b` + +Constructs a value of type `Either a b` from a value of type `b`. + +```javascript +> Right (42) +Right (42) +``` + +#### `Either.@@type :: String` + +Either [type identifier][]. + +```javascript +> type (Right (42)) +'sanctuary-either/Either@1' + +> type.parse (type (Right (42))) +{namespace: 'sanctuary-either', name: 'Either', version: 1} +``` + +#### `Either.fantasy-land/of :: b -⁠> Either a b` + + - `of (Either) (x)` is equivalent to `Right (x)` + +```javascript +> S.of (Either) (42) +Right (42) +``` + +#### `Either.fantasy-land/chainRec :: ((a -⁠> c, b -⁠> c, a) -⁠> Either d c, a) -⁠> Either d b` + +```javascript +> Z.chainRec ( +. Either, +. (next, done, x) => +. x <= 1 ? Left ('!!') : Right (x >= 1000 ? done (x) : next (x * x)), +. 1 +. ) +Left ('!!') + +> Z.chainRec ( +. Either, +. (next, done, x) => +. x <= 1 ? Left ('!!') : Right (x >= 1000 ? done (x) : next (x * x)), +. 2 +. ) +Right (65536) +``` + +#### `Either#@@show :: (Showable a, Showable b) => Either a b ~> () -⁠> String` + + - `show (Left (x))` is equivalent to `'Left (' + show (x) + ')'` + - `show (Right (x))` is equivalent to `'Right (' + show (x) + ')'` + +```javascript +> show (Left ('sqrt undefined for -1')) +'Left ("sqrt undefined for -1")' + +> show (Right ([1, 2, 3])) +'Right ([1, 2, 3])' +``` + +#### `Either#fantasy-land/equals :: (Setoid a, Setoid b) => Either a b ~> Either a b -⁠> Boolean` + + - `Left (x)` is equal to `Left (y)` [iff][] `x` is equal to `y` + according to [`Z.equals`][] + - `Right (x)` is equal to `Right (y)` [iff][] `x` is equal to `y` + according to [`Z.equals`][] + - `Left (x)` is never equal to `Right (y)` + +```javascript +> S.equals (Left ([1, 2, 3])) (Left ([1, 2, 3])) +true + +> S.equals (Right ([1, 2, 3])) (Right ([1, 2, 3])) +true + +> S.equals (Left ([1, 2, 3])) (Right ([1, 2, 3])) +false +``` + +#### `Either#fantasy-land/lte :: (Ord a, Ord b) => Either a b ~> Either a b -⁠> Boolean` + + - `Left (x)` is less than or equal to `Left (y)` [iff][] `x` is less + than or equal to `y` according to [`Z.lte`][] + - `Right (x)` is less than or equal to `Right (y)` [iff][] `x` is less + than or equal to `y` according to [`Z.lte`][] + - `Left (x)` is always less than `Right (y)` + +```javascript +> S.filter (S.lte (Left (1))) ([Left (0), Left (1), Left (2)]) +[Left (0), Left (1)] + +> S.filter (S.lte (Right (1))) ([Right (0), Right (1), Right (2)]) +[Right (0), Right (1)] + +> S.filter (S.lte (Left (1))) ([Right (0), Right (1), Right (2)]) +[] + +> S.filter (S.lte (Right (1))) ([Left (0), Left (1), Left (2)]) +[Left (0), Left (1), Left (2)] +``` + +#### `Either#fantasy-land/concat :: (Semigroup a, Semigroup b) => Either a b ~> Either a b -⁠> Either a b` + + - `concat (Left (x)) (Left (y))` is equivalent to + `Left (concat (x) (y))` + - `concat (Right (x)) (Right (y))` is equivalent to + `Right (concat (x) (y))` + - `concat (Left (x)) (Right (y))` is equivalent to `Right (y)` + - `concat (Right (x)) (Left (y))` is equivalent to `Right (x)` + +```javascript +> S.concat (Left ('abc')) (Left ('def')) +Left ('abcdef') + +> S.concat (Right ([1, 2, 3])) (Right ([4, 5, 6])) +Right ([1, 2, 3, 4, 5, 6]) + +> S.concat (Left ('abc')) (Right ([1, 2, 3])) +Right ([1, 2, 3]) + +> S.concat (Right ([1, 2, 3])) (Left ('abc')) +Right ([1, 2, 3]) +``` + +#### `Either#fantasy-land/map :: Either a b ~> (b -⁠> c) -⁠> Either a c` + + - `map (f) (Left (x))` is equivalent to `Left (x)` + - `map (f) (Right (x))` is equivalent to `Right (f (x))` + +```javascript +> S.map (S.add (1)) (Left ('sqrt undefined for -1')) +Left ('sqrt undefined for -1') + +> S.map (S.add (1)) (Right (99)) +Right (100) +``` + +#### `Either#fantasy-land/bimap :: Either a c ~> (a -⁠> b, c -⁠> d) -⁠> Either b d` + + - `bimap (f) (g) (Left (x))` is equivalent to `Left (f (x))` + - `bimap (f) (g) (Right (x))` is equivalent to `Right (g (x))` + +```javascript +> S.bimap (S.toUpper) (S.add (1)) (Left ('abc')) +Left ('ABC') + +> S.bimap (S.toUpper) (S.add (1)) (Right (99)) +Right (100) +``` + +#### `Either#fantasy-land/ap :: Either a b ~> Either a (b -⁠> c) -⁠> Either a c` + + - `ap (Left (x)) (Left (y))` is equivalent to `Left (x)` + - `ap (Left (x)) (Right (y))` is equivalent to `Left (x)` + - `ap (Right (f)) (Left (x))` is equivalent to `Left (x)` + - `ap (Right (f)) (Right (x))` is equivalent to `Right (f (x))` + +```javascript +> S.ap (Left ('div undefined for 0')) (Left ('sqrt undefined for -1')) +Left ('div undefined for 0') + +> S.ap (Left ('div undefined for 0')) (Right (99)) +Left ('div undefined for 0') + +> S.ap (Right (S.add (1))) (Left ('sqrt undefined for -1')) +Left ('sqrt undefined for -1') + +> S.ap (Right (S.add (1))) (Right (99)) +Right (100) +``` + +#### `Either#fantasy-land/chain :: Either a b ~> (b -⁠> Either a c) -⁠> Either a c` + + - `chain (f) (Left (x))` is equivalent to `Left (x)` + - `chain (f) (Right (x))` is equivalent to `f (x)` + +```javascript +> const sqrt = n => n < 0 ? Left ('sqrt undefined for ' + show (n)) +. : Right (Math.sqrt (n)) + +> S.chain (sqrt) (Left ('div undefined for 0')) +Left ('div undefined for 0') + +> S.chain (sqrt) (Right (-1)) +Left ('sqrt undefined for -1') + +> S.chain (sqrt) (Right (25)) +Right (5) +``` + +#### `Either#fantasy-land/alt :: Either a b ~> Either a b -⁠> Either a b` + + - `alt (Left (x)) (Left (y))` is equivalent to `Left (y)` + - `alt (Left (x)) (Right (y))` is equivalent to `Right (y)` + - `alt (Right (x)) (Left (y))` is equivalent to `Right (x)` + - `alt (Right (x)) (Right (y))` is equivalent to `Right (x)` + +```javascript +> S.alt (Left ('A')) (Left ('B')) +Left ('B') + +> S.alt (Left ('C')) (Right (1)) +Right (1) + +> S.alt (Right (2)) (Left ('D')) +Right (2) + +> S.alt (Right (3)) (Right (4)) +Right (3) +``` + +#### `Either#fantasy-land/reduce :: Either a b ~> ((c, b) -⁠> c, c) -⁠> c` + + - `reduce (f) (x) (Left (y))` is equivalent to `x` + - `reduce (f) (x) (Right (y))` is equivalent to `f (x) (y)` + +```javascript +> S.reduce (S.concat) ([1]) (Left ('sqrt undefined for -1')) +[1] + +> S.reduce (S.concat) ([1]) (Right ([2])) +[1, 2] +``` + +#### `Either#fantasy-land/traverse :: Applicative f => Either a b ~> (TypeRep f, b -⁠> f c) -⁠> f (Either a c)` + + - `traverse (A) (f) (Left (x))` is equivalent to `of (A) (Left (x))` + - `traverse (A) (f) (Right (x))` is equivalent to `map (Right) (f (x))` + +```javascript +> S.traverse (Array) (S.words) (Left ('sqrt undefined for -1')) +[Left ('sqrt undefined for -1')] + +> S.traverse (Array) (S.words) (Right ('foo bar baz')) +[Right ('foo'), Right ('bar'), Right ('baz')] +``` + +#### `Either#fantasy-land/extend :: Either a b ~> (Either a b -⁠> c) -⁠> Either a c` + + - `extend (f) (Left (x))` is equivalent to `Left (x)` + - `extend (f) (Right (x))` is equivalent to `Right (f (Right (x)))` + +```javascript +> S.extend (S.reduce (S.add) (1)) (Left ('sqrt undefined for -1')) +Left ('sqrt undefined for -1') + +> S.extend (S.reduce (S.add) (1)) (Right (99)) +Right (100) +``` + +[Fantasy Land]: https://github.com/fantasyland/fantasy-land/tree/v3.5.0 +[`Z.equals`]: https://github.com/sanctuary-js/sanctuary-type-classes/tree/v9.0.0#equals +[`Z.lte`]: https://github.com/sanctuary-js/sanctuary-type-classes/tree/v9.0.0#lte +[iff]: https://en.wikipedia.org/wiki/If_and_only_if +[type identifier]: https://github.com/sanctuary-js/sanctuary-type-identifiers/tree/v2.0.1 +[type representative]: https://github.com/fantasyland/fantasy-land/tree/v3.5.0#type-representatives diff --git a/package.json b/package.json index 922cd2a..a4b2e76 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "sanctuary-either", - "version": "0.0.0", + "version": "1.0.0", "description": "Fantasy Land -compliant Either type", "license": "MIT", "repository": {