diff --git a/docs/src/pages/docs/crocks/Async.md b/docs/src/pages/docs/crocks/Async.md index f4207a5e0..e83f99dfc 100644 --- a/docs/src/pages/docs/crocks/Async.md +++ b/docs/src/pages/docs/crocks/Async.md @@ -1266,17 +1266,19 @@ eitherToAsync :: Either b a -> Async b a eitherToAsync :: (a -> Either c b) -> a -> Async c b ``` -Used to transform a given `Either` instance to -an `Async` instance, `eitherToAsync` will turn a `Right` instance into +Used to transform a given [`Either`][either] instance to +an `Async` instance, `eitherToAsync` will turn a [`Right`][right] instance into a [`Resolved`](#resolved) instance wrapping the original value contained in the -original `Right`. If a `Left` is provided, then `eitherToAsync` will return -a [`Rejected`](#rejected) instance, wrapping the original `Left` value. +original [`Right`][right]. If a [`Left`][left] is provided, +then `eitherToAsync` will return a [`Rejected`](#rejected) instance, wrapping +the original [`Left`][left] value. Like all `crocks` transformation functions, `eitherToAsync` has two possible -signatures and will behave differently when passed either an `Either` instance -or a function that returns an instance of `Either`. When passed the instance, -a transformed `Async` is returned. When passed an `Either` returning function, -a function will be returned that takes a given value and returns an `Async`. +signatures and will behave differently when passed +an [`Either`][either] instance or a function that returns an instance +of [`Either`][either]. When passed the instance, a transformed `Async` is +returned. When passed an [`Either`][either] returning function, a function will +be returned that takes a given value and returns an `Async`. @@ -1678,6 +1680,9 @@ Resolved('103') [identity]: ../functions/combinators.html#identity [first]: ../monoids/First.html [last]: ../monoids/Last.html -[maybe]: ../crocks/Maybe.html -[just]: ../crocks/Maybe.html#just -[nothing]: ../crocks/Maybe.html#nothing +[maybe]: ./Maybe.html +[just]: ./Maybe.html#just +[nothing]: ./Maybe.html#nothing +[either]: ./Either.html +[left]: ./Either.html#left +[right]: ./Either.html#right diff --git a/docs/src/pages/docs/crocks/Either.md b/docs/src/pages/docs/crocks/Either.md new file mode 100644 index 000000000..1adc3c439 --- /dev/null +++ b/docs/src/pages/docs/crocks/Either.md @@ -0,0 +1,1345 @@ +--- +title: "Either" +description: "Either Crock" +layout: "guide" +functions: ["firsttoeither", "lasttoeither", "maybetoeither", "resulttoeither"] +weight: 40 +--- + +```haskell +Either c a = Left c | Right a +``` + +`Either` is the canonical `Sum` type and is the base of all other `Sum` types +included in `crocks`, such as [`Maybe`][maybe] and [`Async`][async] to name a +few. Defined as a tagged union type, it captures the essence of disjunction as +it provides either a `Left` value or a `Right` value and not both. + +Unlike [`Maybe`][maybe], which fixes its "left side", or [`Nothing`][nothing] to +a `()` (unit), `Either` is a functor in both it's `Left` and `Right` sides. This +allows for the ability to vary the type on either side and is akin to the +imperative `if...else` trees that are common in programming. + +Like most other types in `crocks`, `Either` has a right bias in regard to +instance methods like `map`, `ap` and `chain`. This behavior can be used to +formally capture Error handling as the `Left` value will be maintained +throughout subsequent flows. + +```javascript +import Either from 'crocks/Either' + +import compose from 'crocks/helpers/compose' +import ifElse from 'crocks/logic/ifElse' +import isNumber from 'crocks/predicates/isNumber' +import map from 'crocks/pointfree/map' + +const { Left, Right } = Either + +// err :: a -> String +const err = val => + `${typeof val} is not an accepted type` + +// add :: Number -> Number -> Number +const add = + x => y => x + y + +// validate :: a -> Either String Number +const validate = ifElse( + isNumber, + Right, + compose(Left, err) +) + +// flow :: a -> Either String Number +const flow = compose( + map(add(10)), + validate +) + +flow(32) +//=> Right 42 + +flow('32') +//=> Left "string is not an accepted type" + +flow(true) +//=> Left "boolean is not an accepted type" +``` + +
+ +## Implements +`Setoid`, `Semigroup`, `Functor`, `Alt`, `Apply`, `Traversable`, `Chain`, `Applicative`, `Monad` + +
+ +
+ +## Construction + +```haskell +Either :: a -> Either c a +``` + +An `Either` is typically constructed by using one of the instance constructors +provided on the `TypeRep`: [`Left`](#left) or [`Right`](#right). For consistency, +an `Either` can be constructed using its `TypeRep` as a constructor. The +constructor is a unary function that accepts any type `a` and will return a +`Right` instance, wrapping the value it was passed. + +```javascript +import Either from 'crocks/Either' +import equals from 'crocks/pointfree/equals' + +Either(90) +//=> Right 90 + +Either.of(90) +//=> Right 90 + +Either.Right(90) +//=> Right 90 + +equals( + Either.Right([ 1, 2, 3 ]), + Either.of([ 1, 2, 3 ]) +) +//=> true + +equals( + Either.of({ a: 100 }), + Either({ a: 100 }) +) +//=> true +``` + +
+ +
+ +## Constructor Methods + +#### Left + +```haskell +Either.Left :: c -> Either c a +``` + +Used to construct a `Left` instance of an `Either` that represents the +`false` portion of a disjunction. The `Left` constructor takes a value of any +type and returns a `Left` instance wrapping the value passed to the constructor. + +When an instance is a `Left`, most `Either` returning methods on +the instance will do nothing to the wrapped value and return another `Left` with +the same initial value the `Left` instance was constructed with. + +```javascript +import Either from 'crocks/Either' + +import chain from 'crocks/pointfree/chain' +import compose from 'crocks/helpers/compose' +import isString from 'crocks/predicates/isString' +import ifElse from 'crocks/logic/ifElse' + +const { Left, Right } = Either + +// yell :: String -> String +const yell = + x => `${x.toUpperCase()}!` + +// safeYell :: a -> Either a String +const safeYell = ifElse( + isString, + compose(Right, yell), + Left +) + +Right('excite') + .map(yell) +//=> Right "EXCITE!" + +Left('whisper') + .map(yell) +//=> Left "whisper" + +chain(safeYell, Right('outside voice')) +//=> Right "OUTSIDE VOICE!" + +chain(safeYell, Left({ level: 'inside voice' })) +//=> Left { level: 'inside voice' } +``` + +#### Right + +```haskell +Either.Right :: a -> Either c a +``` + +Used to construct a `Right` instance of the an `Either` that represents +the `true` portion of a disjunction. The `Right` constructor takes any value and +will return a new `Right` instance wrapping the value provided. + +```javascript +import Either from 'crocks/Either' + +import compose from 'crocks/helpers/compose' +import composeK from 'crocks/helpers/composeK' +import ifElse from 'crocks/logic/ifElse' +import isNumber from 'crocks/predicates/isNumber' + +const { Left, Right } = Either + +// validate :: (b -> Boolean) -> Either c a +const validate = pred => + ifElse(pred, Right, Left) + +// add10 :: Number -> Number +const add10 = + x => x + 10 + +Right(10) + .map(add10) +//=> Right 20 + +Left('Not A Number') + .map(add10) +//=> Left "Not A Number" + +// validNumber :: b -> Either c Number +const validNumber = + validate(isNumber) + +validNumber('60') +//=> Left "60" + +validNumber(null) +//=> Left null + +validNumber(60) +//=> Right 60 + +// safeAdd10 :: b -> Either c Number +const safeAdd10 = composeK( + compose(Right, add10), + validNumber +) + +safeAdd10([ 7 ]) +//=> Left [ 7 ] + +safeAdd10(null) +//=> Left null + +safeAdd10(5) +//=> Right 15 + +// isLarge :: Number -> Either Number Number +const isLarge = + validate(x => x >= 10) + +// isLargeNumber :: b -> Either c Number +const isLargeNumber = + composeK(isLarge, validNumber) + +// add10ToLarge :: b -> Either c Number +const add10ToLarge = + composeK(safeAdd10, isLargeNumber) + +add10ToLarge() +//=> Left undefined + +add10ToLarge('40') +//=> Left "40" + +add10ToLarge(5) +//=> Left 5 + +add10ToLarge(10) +//=> Right 20 +``` + +#### of + +```haskell +Either.of :: a -> Either c a +``` + +Used to lift any value into an `Either` as a `Right`, `of` is used mostly by +helper functions that work "generically" with instances of +either `Applicative` or `Monad`. When working specifically with +the `Either` type, the [`Right`](#right) constructor should be used. Reach +for `of` when working with functions that will work with +ANY `Applicative`/`Monad`. + +```javascript +import Either from 'crocks/Either' + +const { Right } = Either + +Either.of('some string') +//=> Right "some string" + +Either.of(undefined) +//=> Right undefined + +Either('some string') +//=> Right "some string" + +Either(undefined) +//=> Right undefined + +Right('some string') +//=> Right "some string" + +Right(undefined) +//=> Right undefined +``` + +
+ +
+ +## Instance Methods + +#### equals + +```haskell +Either c a ~> b -> Boolean +``` + +Used to compare the underlying values of two `Either` instances for equality by +value, `equals` takes any given argument and returns `true` if the passed +arguments is a `Either` of the same instance with an underlying value equal to +the underlying value of the `Either` the method is being called on. If the +passed argument is not an `Either` of the same instance or the underlying values +are not equal, `equals` will return `false`. + +```javascript +import Either from 'crocks/Either' +import equals from 'crocks/pointfree/equals' + +const { Left, Right } = Either + +Right(null) + .equals(Right(null)) +//=> true + +Left('happy') + .equals(Left('happy')) +//=> true + +Left('sad') + .equals(Right('sad')) +//=> false + +// by value, not reference for most types +Right([ 1, { a: 2 }, 'string' ]) + .equals(Right([ 1, { a: 2 }, 'string' ])) +//=> true + +equals(Right('sad'), 'sad') +//=> false +``` + +#### concat + +```haskell +Semigroup s => Either c s ~> Either c s -> Either c s +``` + +When an underlying `Right` value of a given `Either` is fixed to +a `Semigroup`, `concat` can be used to concatenate another `Right` instance +with an underlying `Semigroup` of the same type. Expecting an `Either` wrapping +a `Semigroup` of the same type, `concat` will give back a new `Either` instance +wrapping the result of combining the two underlying `Semigroup`s. When called on +a `Left` instance, `concat` will return a `Left` containing the initial value. + +```javascript + +import Either from 'crocks/Either' + +import Assign from 'crocks/Assign' +import compose from 'crocks/helpers/compose' +import concat from 'crocks/pointfree/concat' +import flip from 'crocks/combinators/flip' +import ifElse from 'crocks/logic/ifElse' +import isObject from 'crocks/predicates/isObject' +import mapReduce from 'crocks/helpers/mapReduce' + +const { Left, Right } = Either + +Right([ 1, 2 ]) + .concat(Right([ 4, 5 ])) +//=> Right [ 1, 2, 3, 4 ] + +Right([ 1, 2 ]) + .concat(Left('Error')) +//=> Left "Error" + +// lift :: Object -> Either c Assign +const lift = + compose(Right, Assign) + +// liftObject :: b -> Either c Assign +const liftObject = + ifElse(isObject, lift, Left) + +// Foldable f => fold :: f * -> Either * Assign +const fold = mapReduce( + liftObject, + flip(concat), + Either(Assign.empty()) +) + +fold([ { a: 'a' }, { b: 'b' } ]) +//=> Right Assign { a: "a", b: "b" } + +fold([ + { a: 'a' }, null, { c: 'c' } +]) +//=> Left null +``` + +#### map + +```haskell +Either c a ~> (a -> b) -> Either c b +``` + +Used to apply transformations to values `Right` instances of `Either`, `map` +takes a function that it will lift into the context of the `Either` and apply to +it the wrapped value. When ran on a `Right` instance, `map` will apply the +wrapped value to the provided function and return the result in a +new `Right` instance. + +```javascript +import Either from 'crocks/Either' + +import compose from 'crocks/helpers/compose' +import ifElse from 'crocks/logic/ifElse' +import isNumber from 'crocks/predicates/isNumber' +import map from 'crocks/pointfree/map' +import objOf from 'crocks/helpers/objOf' + +const { Left, Right } = Either + +// add :: Number -> Number -> Number +const add = + x => y => x + y + +Right(25) + .map(add(10)) +//=> Right 35 + +Left('Some String') + .map(add(10)) +//=> Left "Some String" + +// numberOr :: a -> Either b Number +const numberOr = ifElse( + isNumber, Right, Left +) + +// add10 -> a -> Either b Number +const add10 = compose( + map(add(10)), + numberOr +) + +add10(45) +//=> Right 55 + +add10('some string') +//=> Left "some string" + +const processResult = compose( + map(compose(objOf('result'), add(20))), + numberOr +) + +processResult({ a: 57 }) +//=> Left { a: 57 } + +processResult(57) +//=> Right{ result: 77 } +``` + +#### alt + +```haskell +Either c a ~> Either c a -> Either c a +``` + +Providing a means for a fallback or alternative value, `alt` combines two +`Either` instances and will return the first `Right` it encounters or the +last `Left` if it does not encounter a `Right`. + +```javascript +import Either from 'crocks/Either' + +const { Left, Right } = Either + +Right(45) + .alt(Right(97)) + .alt(Left(false)) +//=> Right 45 + +Left('String') + .alt(Left('Another String')) + .alt(Left('Final String')) +//=> Left "Final String" + +Left('error') + .alt(Right({ passed: true })) +//=> Right { passed: true } +``` + +#### bimap + +```haskell +Either c a ~> ((c -> d), (a -> b)) -> Either d b +``` + +The types and values that make up an `Either` can vary independently in both +the `Left` and `Right` instances of the `Either`. While [`map`](#map) can be +used to apply a transformation to a `Right` instance, `bimap` allows +transformations for either. + +`bimap` takes two mapping functions as its arguments. The first function is used +to map a `Left` instance, while the second maps a `Right`. `Either` only +provides a means to map a `Right` instance exclusively using [`map`](#map). If +the need arises to map a `Left` instance exclusively, then `bimap` can be used, +passing the mapping function to the first argument and +an [`identity`][identity] to the second. + +```javascript +import Either from 'crocks/Either' + +import bimap from 'crocks/pointfree/bimap' +import compose from 'crocks/helpers/compose' +import ifElse from 'crocks/logic/ifElse' +import objOf from 'crocks/helpers/objOf' + +const { Left, Right } = Either + +// lte :: Number -> Number -> Boolean +const lte = + x => y => y <= x + +// gt10 :: Number -> Either Number Number +const gt10 = + ifElse(lte(10), Left, Right) + +// offsetBy :: Number -> Number -> Number +const offsetBy = + x => y => x + y + +// scaleBy :: Number -> Number -> Number +const scaleBy = + x => y => x * y + +// compute :: Number -> Either Number Number +const compute = compose( + bimap(scaleBy(10), offsetBy(10)), + gt10 +) + +compute(10) +//=> Left 100 + +compute(20) +//=> Right 30 + +// arrayOf :: a -> [ a ] +const arrayOf = + x => [ x ] + +// resultOf :: a -> { result: a } +const resultOf = + objOf('result') + +// format :: Either c a -> Either [ c ] { result: a } +const format = + bimap(arrayOf, resultOf) + +format(Left(100)) +//=> Left [ 100 ] + +format(Right(30)) +//=> Right { result: 30 } + +// processAndFormat :: Either Number Number -> Either [ Number ] { result: Number } +const processAndFormat = bimap( + compose(arrayOf, scaleBy(10)), + compose(resultOf, offsetBy(10)) +) + +// flow :: Number -> Either [ Number ] +const flow = compose( + processAndFormat, + gt10 +) + +flow(10) +//=> Left [ 100 ] + +flow(20) +//=> Right { result: 30 } +``` + +#### ap + +```haskell +Either c (a -> b) ~> Either c a -> Either c b +``` + +Short for apply, `ap` is used to apply an `Either` instance containing a value +to another `Either` instance that contains a function, resulting in +new `Either` instance containing the result of the application. `ap` requires +that it is called on either a `Left` containing anything or a `Right` that +wraps a curried polyadic function. + +When either instance is a `Left`, `ap` will return a `Left` containing the +original value. This can be used to safely combine multiple values under a +given combination function. If any of the inputs results in a `Left` than they +will never be applied to the function and not provide exceptions or undesired +results. + +```javascript +import Either from 'crocks/Either' + +import assign from 'crocks/helpers/assign' +import assoc from 'crocks/helpers/assoc' +import compose from 'crocks/helpers/compose' +import identity from 'crocks/combinators/identity' +import ifElse from 'crocks/logic/ifElse' +import isObject from 'crocks/predicates/isObject' +import objOf from 'crocks/helpers/objOf' + +const { Left, Right } = Either + +// objectOr :: a -> Either c Object +const objectOr = + ifElse(isObject, Right, Left) + +// Error :: { error: a, passed: Boolean } +// error :: a -> Error +const error = compose( + assoc('passed', false), + objOf('error') +) + +// setPassed :: Either c Object -> Either Error Object +const setPassed = m => + Either.of(assoc('passed', true)) + .ap(m) + .bimap(error, identity) + +setPassed(Right({ a: 'awesome' })) +//=> Right { a: "awesome", passed: true } + +setPassed(Left({ a: 'not so much' })) +//=> Left { error: "not so much", passed: false } + +// process :: a -> Either Object Object +const process = + compose(setPassed, objectOr) + +process({ a: 'awesome' }) +//=> Right { a: "awesome", passed: true } + +process('I am string') +//=> Left { error: "I am string", passed: false } + +// assignOr :: (Either c Object, Either c Object) -> Either c Object +const assignOr = (x, y) => + x.map(assign).ap(y) + +assignOr(Right({ b: 'also awesome' }), Right({ a: 'awesome' })) +//=> Right { a: "awesome", b: "also awesome" } + +assignOr(Right({ b: 'also awesome' }), Left('not so awesome')) +//=> Left "not so awesome" + +assignOr(Left({ b: 'first' }), Left({ b: 'second' })) +//=> Left { b: "first" } +``` + +#### sequence + +```haskell +Apply f => Either c (f a) ~> (b -> f b) -> f (Either c a) +Applicative f => Either c (f a) ~> TypeRep f -> f (Either c a) +``` + +When an instance of `Either` wraps an `Apply` instance, `sequence` can be used +to swap the type sequence. `sequence` requires either +an `Applicative TypeRep` or an `Apply` returning function is provided for its +argument. This will be used in the case that the `Either` instance is a `Left`. + +`sequence` can be derived from [`traverse`](#traverse) by passing it +an [`identity`][identity] function. + +```javascript +import Either from 'crocks/Either' + +import Identity from 'crocks/Identity' + +const { Left, Right } = Either + +// arrayOf :: a -> [ a ] +const arrayOf = + x => [ x ] + +Right([ 1, 2, 3 ]) + .sequence(arrayOf) +//=> [ Right 1, Right 2, Right 3 ] + +Left('no array here') + .sequence(arrayOf) +//=> [ Left "no array here" ] + +Right(Identity.of(42)) + .sequence(Identity) +//=> Identity (Right 42) + +Left(0) + .sequence(Identity) +//=> Identity (Left 0) +``` + +#### traverse + +```haskell +Apply f => Either c a ~> (d -> f d), (a -> f b)) -> f Either c b +Applicative f => Either c a ~> (TypeRep f, (a -> f b)) -> f Either c b +``` + +Used to apply the "effect" of an `Apply` to a value inside of an `Either`, +`traverse` combines both the "effects" of the `Apply` and the `Either` by +returning a new instance of the `Apply`, wrapping the result of the +`Apply`s "effect" on the value in the supplied `Either`. + +`traverse` requires either an `Applicative TypeRep` or an `Apply` returning +function as its first argument and a function that is used to apply the "effect" +of the target `Apply` to the value inside of the `Either`. This will be used in +the case that the `Either` instance is a `Left`. Both arguments must provide +an instance of the target `Apply`. + +```javascript +import Either from 'crocks/Either' + +import Pair from 'crocks/Pair' +import State from 'crocks/State' +import Sum from 'crocks/Sum' +import constant from 'crocks/combinators/constant' +import ifElse from 'crocks/logic/ifElse' +import traverse from 'crocks/pointfree/traverse' + +const { Left, Right } = Either +const { get } = State + +// tallyOf :: a -> [ a ] +const tallyOf = + x => Pair(Sum.empty(), x) + +// incBy :: Number -> Pair Sum Number +const incBy = + x => Pair(Sum(x), x) + +Right(12) + .traverse(tallyOf, incBy) +//=> Pair( Sum 12, Right 12 ) + +Left(true) + .traverse(tallyOf, incBy) +//=> Pair( Sum 0, Left true ) + +// lte10 :: Number -> Either Number Number +const lte10 = + ifElse(x => x <= 10, Right, Left) + +// update :: Number -> State Number Number +const update = x => + State.modify(state => x + state) + .chain(constant(get())) + +// updateSmall :: () => State Number Number +const updateSmall = () => + get(lte10) + .chain(traverse(State, update)) + +updateSmall() + .runWith(3) +//=> Pair( Right 6, 6 ) + +updateSmall() + .chain(updateSmall) + .runWith(3) +//=> Pair( Left 12, 12 ) + +updateSmall() + .chain(updateSmall) + .chain(updateSmall) + .runWith(3) +//=> Pair( Left 12, 12 ) + +updateSmall() + .chain(updateSmall) + .chain(updateSmall) + .runWith(30) +//=> Pair( Left 30, 30 ) +``` + +#### chain + +```haskell +Either c a ~> (a -> Either c b) -> Either c b +``` + +Combining a sequential series of transformations that capture disjunction can be +accomplished with `chain`. `chain` expects a unary, `Either` returning function +as its argument. When invoked on a `Left`, `chain` will not run the function, +but will instead return another `Left` wrapping the original value. When called +on a `Left` however, the inner value will be passed to the provided function, +returning the result as the new instance. + +```javascript +import Either from 'crocks/Either' + +import ifElse from 'crocks/logic/ifElse' +import isString from 'crocks/predicates/isString' +import maybeToEither from 'crocks/Either/maybeToEither' +import prop from 'crocks/Maybe/prop' +import propEq from 'crocks/predicates/propEq' + +const { Left, Right } = Either + +// lift :: (b -> Boolean) -> b -> Either c a +const lift = pred => + ifElse(pred, Right, Left) + +// isPassed :: b -> Either c Object +const isPassed = + lift(propEq('passed', true)) + +isPassed({ value: 'Nope' }) +// Left { value: "Nope" } + +isPassed({ value: 'yes', passed: true }) +// Right { value: "yes", passed: true } + +// stringOr :: b -> Either c String +const stringOr = + lift(isString) + +// valueOr :: b -> Either c a +const valueOr = x => + maybeToEither(x, prop('value'), x) + +// getStringValue :: b -> Either c String +const getStringValue = x => + isPassed(x) + .chain(valueOr) + .chain(stringOr) + +getStringValue({ + value: 'So good', + passed: true +}) +//=> Right "So Good" + +getStringValue({ + value: 'Not passed' +}) +//=> Left { value: "Not passed" } + +getStringValue({ + value: 33, + passed: true +}) +//=> Right "So Good" + +getStringValue({ + value: 33, + passed: true +}) +//=> Left 33 +``` + +#### coalesce + +```haskell +Either c a ~> ((c -> b), (a -> b)) -> Either c b +``` + +Used to take a `Left` instance and not only map its internal value, but also +to "promote" it to a `Right` instance. `coalesce` takes two unary functions as +its arguments and will return a new `Right` instance. + +The first function is used when invoked on a `Left` and will return a `Right` +instance, wrapping the result of the function. The second function is used when +`coalesce` is invoked on a `Right` and is used to map the original value, +returning a new `Right` instance wrapping the result of the second function. + +```javascript +import Either from 'crocks/Either' + +import assoc from 'crocks/helpers/assoc' +import coalesce from 'crocks/pointfree/coalesce' +import compose from 'crocks/helpers/compose' +import identity from 'crocks/combinators/identity' +import hasProp from 'crocks/predicates/hasProp' +import ifElse from 'crocks/logic/ifElse' +import map from 'crocks/pointfree/map' +import mapProps from 'crocks/helpers/mapProps' + +const { Left, Right } = Either + +// inc :: Number -> Number -> Number +const inc = + x => x + 1 + +Right(45) + .coalesce(identity, inc) +//=> Right 46 + +Left(45) + .coalesce(identity, inc) +//=> Right 45 + +// Record :: { value: Number } +// hasValue :: Object -> Either Object Record +const hasValue = + ifElse(hasProp('value'), Right, Left) + +hasValue({ a: 45 }) +// Left { a: 45 } + +hasValue({ value: 45 }) +// Right { value: 45 } + +// defaultValue :: Either Object Record -> Either Object Record +const defaultValue = + coalesce(assoc('value', 0), identity) + +// incValue :: Either Object Record -> Either c Record +const incValue = compose( + map(mapProps({ value: inc })), + defaultValue, + hasValue +) + +incValue({ value: 45 }) + +//=> Right { value: 46 } + +incValue({ a: 44 }) +//=> Right { a: 44, value: 1 } +``` + +#### swap + +```haskell +Either c a ~> ((c -> d), (a -> b)) -> Either b d +``` + +Used to map the value of an `Either` instance and transform a `Left` into a +`Right` or a `Right` into a `Left`, `swap` takes two functions as its arguments. +The first function is used to map and transform a `Left` into a `Right`, +while the second maps and transforms a `Right` into a `Left`. If no mapping of +the contained values is required for either instance, +then [`identity`][identity] functions can be used in one or both arguments. + +```javascript +import Either from 'crocks/Either' + +import identity from 'crocks/combinators/identity' +import swap from 'crocks/pointfree/swap' + +const { Left, Right } = Either + +// swapTypes :: Either c a -> Either a c +const swapTypes = + swap(identity, identity) + +swapTypes(Left(45)) +//=> Right 45 + +swapTypes(Right(23)) +//=> Left 23 + +// toString :: Number -> String +const toString = + x => x.toString() + +// toNumber :: String -> Number +const toNumber = + x => parseInt(x) + +// swapValues :: Either Number String -> Either Number String +const swapValues = + swap(toString, toNumber) + +swapValues(Left(23)) +//=> Right "23" + +swapValues(Right('23')) +//=> Left 23 +``` + +#### either + +```haskell +Either c a ~> ((c -> b), (a -> b)) -> b +``` + +Used as a means to map and extract a value from an `Either` based on the +context, `either` takes two functions as its arguments. The first will map any +the value `Left` in a left instance. While the second is used to map any `Right` +instance value. The function will return the result of whichever function is +used to map. + +```javascript +import Either from 'crocks/Either' + +import curry from 'crocks/helpers/curry' +import either from 'crocks/pointfree/either' +import identity from 'crocks/combinators/identity' +import objOf from 'crocks/helpers/objOf' + +const { Left, Right } = Either + +// toObject :: String -> Either a Object -> Object +const toObject = curry( + key => either(objOf(key), identity) +) + +toObject('num', Left(44)) +//=> { num: 44 } + +toObject('num', Right({ string: 'a string' })) +//=> { string: 'a string' } +``` + +
+ +
+ +## Transformation Functions + +#### firstToEither + +`crocks/Either/firstToEither` + +```haskell +firstToEither :: c -> First a -> Either c a +firstToEither :: c -> (a -> First b) -> a -> Either c a +``` + +Used to transform a given [`First`][first] instance to an `Either` +instance, `firstToEither` will turn a non-empty instance into +a [`Right`](#right) wrapping the original value contained within +the [`First`][first]. + +The [`First`][first] datatype is based on a [`Maybe`][maybe] and as such its +is fixed to a `()` (unit) type. As a means to allow for convenient +transformation, `firstToEither` takes a default [`Left`](#left) value as the +first argument. This value will be wrapped in a +resulting [`Left`](#left) instance in the case of empty. + +Like all `crocks` transformation functions, `firstToEither` has two possible +signatures and will behave differently when passed either +a [`First`][first] instance or a function that returns an instance +of [`First`][first]. When passed the instance, a transformed `Either` is +returned. When passed a [`First`][first] returning function, a function will be +returned that takes a given value and returns a `Either`. + +```javascript +import Either from 'crocks/Either' + +import First from 'crocks/First' +import and from 'crocks/logic/and' +import firstToEither from 'crocks/Either/firstToEither' +import isNumber from 'crocks/predicates/isNumber' +import map from 'crocks/pointfree/map' +import mconcatMap from 'crocks/helpers/mconcatMap' +import safe from 'crocks/Maybe/safe' + +const { Right } = Either + +// sorry :: First a -> Either String a +const sorry = + firstToEither('Sorry Charlie') + +sorry(First.empty()) +//=> Left "Sorry Charlie" + +sorry(First('So Good')) +//=> Right "So Good" + +// gte :: Number -> Number -> Boolean +const gte = + y => x => x >= y + +// isValid :: a -> Boolean +const isValid = + and(isNumber, gte(30)) + +// firstValid :: a -> First Number +const firstValid = + mconcatMap(First, safe(isValid)) + +// data :: [ * ] +const data = + [ 1, '200', 60, 300 ] + +Right(data) + .chain(sorry(firstValid)) +//=> Right 60 + +Right(data) + .map(map(x => x.toString())) + .chain(sorry(firstValid)) +//=> Left "Sorry Charlie" +``` + +#### lastToEither + +`crocks/Either/lastToEither` + +```haskell +lastToEither :: c -> Last a -> Either c a +lastToEither :: c -> (a -> Last b) -> a -> Either c a +``` + +Used to transform a given [`Last`][last] instance to +an `Either`, `lastToEither` will turn a non-empty [`Last`][last] instance into +a [`Right`](#right) instance wrapping the original value contained in the +original non-empty. + +The [`Last`][last] datatype is based on a [`Maybe`][maybe] and as such its left +or empty value is fixed to a `()` (unit) type. As a means to allow for +convenient transformation, `lastToEither` takes a default [`Left`](#left) value +as the first argument. This value will be wrapped in a +resulting [`Left`](#left) instance, in the case of empty. + +Like all `crocks` transformation functions, `lastToEither` has two possible +signatures and will behave differently when passed either +a [`Last`][last] instance or a function that returns an instance +of [`Last`][last]. When passed the instance, a transformed `Either` is returned. +When passed a [`Last`][last] returning function, a function will be returned +that takes a given value and returns an `Either`. + +```javascript +import Either from 'crocks/Either' + +import Last from 'crocks/Last' +import and from 'crocks/logic/and' +import compose from 'crocks/helpers/compose' +import concat from 'crocks/pointfree/concat' +import lastToEither from 'crocks/Either/lastToEither' +import isString from 'crocks/predicates/isString' +import map from 'crocks/pointfree/map' +import mconcatMap from 'crocks/helpers/mconcatMap' +import safe from 'crocks/Maybe/safe' +import when from 'crocks/logic/when' + +const { Right } = Either + +// sorry :: Last a -> Either String a +const sorry = + lastToEither('Sorry Charlie') + +sorry(Last.empty()) +//=> Left "Sorry Charlie" + +sorry(Last('So Good')) +//=> Right "So Good" + +// lte :: Number -> Number -> Boolean +const lte = + y => x => x <= y + +// length :: String -> Number +const length = + x => x.length + +// isValid :: a -> Boolean +const isValid = + and(isString, compose(lte(3), length)) + +// lastValid :: a -> Last Number +const lastValid = + mconcatMap(Last, safe(isValid)) + +// data :: [ * ] +const data = + [ 1, '200', 60, 300 ] + +Right(data) + .chain(sorry(lastValid)) +//=> Right "200" + +Right(data) + .map(map(when(isString, concat('!')))) + .chain(sorry(lastValid)) +//=> Left "Sorry Charlie" +``` + +#### maybeToEither + +`crocks/Either/maybeToEither` + +```haskell +maybeToEither :: c -> Maybe a -> Either c a +maybeToEither :: c -> (a -> Maybe b) -> a -> Either c a +``` + +Used to transform a given [`Maybe`][maybe] instance to +an `Either` instance, `maybeToEither` will turn a [`Just`][just] instance into +a [`Right`](#right) instance wrapping the original value contained in the +original [`Just`][just]. + +A [`Nothing`][nothing] instance is fixed to a `()` type and as such can only +ever contain a value of `undefined`. As a means to allow for convenient +transformation, `maybeToEither` takes a default [`Left`](#left) value +as the first argument. This value will be wrapped in a +resulting [`Left`](#left) instance, in the case of [`Nothing`][nothing]. + +Like all `crocks` transformation functions, `maybeToEither` has two possible +signatures and will behave differently when passed either +a [`Maybe`][maybe] instance or a function that returns an instance +of [`Maybe`][maybe]. When passed the instance, a transformed `Either` is +returned. When passed a [`Maybe`][maybe] returning function, a function will be +returned that takes a given value and returns an `Either`. + +```javascript +import Either from 'crocks/Either' + +import Maybe from 'crocks/Maybe' +import compose from 'crocks/helpers/compose' +import fanout from 'crocks/helpers/fanout' +import identity from 'crocks/combinators/identity' +import isObject from 'crocks/predicates/isObject' +import maybeToEither from 'crocks/Either/maybeToEither' +import merge from 'crocks/Pair/merge' +import safe from 'crocks/Maybe/safe' + +const { Nothing, Just } = Maybe +const { Right } = Either + +maybeToEither(false, Nothing()) +//=> Left false + +maybeToEither(false, Just(true)) +//=> Right true + +// isValid :: a -> Either b Object +const isValid = compose( + merge(maybeToEither), + fanout(identity, safe(isObject)) +) + +Right('I am String') + .chain(isValid) +//=> Left "I am String" + +Right({ key: 'value' }) + .chain(isValid) +//=> Right { key: "value" } +``` + +#### resultToEither + +`crocks/Either/resultToEither` + +```haskell +resultToEither :: Result e a -> Either e a +resultToEither :: (a -> Result e b) -> a -> Either e a +``` + +Used to transform a given `Result` instance to +an `Either` instance, `resultToEither` will turn an `Ok` instance into +a [`Right`](#right) instance wrapping the value contained in the +original `Ok`. If an `Err` is provided, then `resultToEither` will return +a [`Left`](#left) instance, wrapping the original `Err` value. + +Like all `crocks` transformation functions, `resultToEither` has two possible +signatures and will behave differently when passed either a `Result` instance +or a function that returns an instance of `Result`. When passed the instance, +a transformed `Either` is returned. When passed a `Result` returning function, +a function will be returned that takes a given value and returns an `Either`. + +```javascript +import Either from 'crocks/Either' + +import Result from 'crocks/Result' +import assign from 'crocks/helpers/assign' +import compose from 'crocks/helpers/compose' +import composeK from 'crocks/helpers/composeK' +import fanout from 'crocks/helpers/fanout' +import isNumber from 'crocks/predicates/isNumber' +import liftA2 from 'crocks/helpers/liftA2' +import map from 'crocks/pointfree/map' +import maybeToResult from 'crocks/Result/maybeToResult' +import merge from 'crocks/Pair/merge' +import objOf from 'crocks/helpers/objOf' +import prop from 'crocks/Maybe/prop' +import resultToEither from 'crocks/Either/resultToEither' +import safeLift from 'crocks/Maybe/safeLift' + +const { Err, Ok } = Result + +resultToEither(Err('no good')) +//=> Left "no good" + +resultToEither(Ok('so good')) +//=> Right "so good" + +// safeInc :: a -> Maybe Number +const safeInc = + safeLift(isNumber, x => x + 1) + +// incProp :: String -> a -> Maybe Number +const incProp = key => + composeK(safeInc, prop(key)) + +// incResult :: String -> a -> Result [ String ] Object +const incResult = key => maybeToResult( + [ `${key} is not valid` ], + compose(map(objOf(key)), incProp(key)) +) + +// incThem :: a -> Result [ String ] Object +const incThem = compose( + merge(liftA2(assign)), + fanout(incResult('b'), incResult('a')) +) + +Either.of({}) + .chain(resultToEither(incThem)) +//=> Left [ "b is not valid", "a is not valid" ] + +Either.of({ a: 33 }) + .chain(resultToEither(incThem)) +//=> Left [ "b is not valid" ] + +Either.of({ a: 99, b: '41' }) + .chain(resultToEither(incThem)) +//=> Left [ "b is not valid" ] + +Either.of({ a: 99, b: 41 }) + .chain(resultToEither(incThem)) +//=> Right { a: 100, b: 42 } +``` + +
+ +[async]: ./Async.html +[identity]: ../functions/combinators.html#identity +[first]: ../monoids/First.html +[last]: ../monoids/Last.html +[maybe]: ./Maybe.html +[nothing]: ./Maybe.html#nothing +[just]: ./Maybe.html#just diff --git a/docs/src/pages/docs/crocks/Maybe.md b/docs/src/pages/docs/crocks/Maybe.md index ce5561e16..0c188783b 100644 --- a/docs/src/pages/docs/crocks/Maybe.md +++ b/docs/src/pages/docs/crocks/Maybe.md @@ -463,7 +463,6 @@ a function that it will lift into the context of the `Maybe` and apply to it the wrapped value. When ran on a `Just` instance, `map` will apply the wrapped value to the provided function and return the result in a new `Just` instance. - ```javascript import Maybe from 'crocks/Maybe' @@ -651,7 +650,8 @@ fullName({ first: 'Lizzy' }) #### sequence ```haskell -Applicative TypeRep t, Apply f => Maybe (f a) ~> (t | (b -> f b)) -> f (Maybe a) +Apply f => Maybe (f a) ~> (b -> f b) -> f (Maybe a) +Applicative f => Maybe (f a) ~> TypeRep f -> f (Maybe a) ``` When an instance of `Maybe` wraps an `Apply` instance, `sequence` can be used to @@ -684,7 +684,8 @@ seqId(Nothing()) #### traverse ```haskell -Applicative TypeRep t, Apply f => Maybe a ~> ((t | (c -> f c)), (a -> f b)) -> f Maybe b +Apply f => Maybe a ~> (c -> f c), (a -> f b)) -> f Maybe b +Applicative f => Maybe a ~> (TypeRep f, (a -> f b)) -> f Maybe b ``` Used to apply the "effect" of an `Apply` to a value inside of a `Maybe`, @@ -1331,18 +1332,19 @@ eitherToMaybe :: Either b a -> Maybe a eitherToMaybe :: (a -> Either c b) -> a -> Maybe b ``` -Used to transform a given `Either` instance to a `Maybe` -instance, `eitherToMaybe` will turn a `Right` instance into a `Just` wrapping -the original value contained in the `Right`. All `Left` instances will map to -a `Nothing`, mapping the originally contained value to a `Unit`. Values on the -`Left` will be lost and as such this transformation is considered lossy in -that regard. +Used to transform a given [`Either`][either] instance to a `Maybe` +instance, `eitherToMaybe` will turn a [`Right`][right] instance into +a [`Just`](#just) wrapping the original value contained in the [`Right`][right]. +All [`Left`][left] instances will map to a [`Nothing`](#nothing), mapping the +originally contained value to a `Unit`. Values on the [`Left`][left] will be +lost and as such this transformation is considered lossy in that regard. Like all `crocks` transformation functions, `eitherToMaybe` has two possible -signatures and will behave differently when passed either an `Either` instance -or a function that returns an instance of `Either`. When passed the instance, -a transformed `Maybe` is returned. When passed an `Either` returning function, -a function will be returned that takes a given value and returns a `Maybe`. +signatures and will behave differently when passed either +an [`Either`][either] instance or a function that returns an instance +of [`Either`][either]. When passed the instance, a transformed `Maybe` is +returned. When passed an [`Either`][either] returning function, a function will +be returned that takes a given value and returns a `Maybe`. ```javascript import Maybe from 'crocks/Maybe' @@ -1394,16 +1396,17 @@ firstToMaybe :: First a -> Maybe a firstToMaybe :: (a -> First b) -> a -> Maybe b ``` -Used to transform a given `First` instance to a `Maybe` -instance, `firstToMaybe` will turn a non-empty instance into a `Just` wrapping -the original value contained within the `First`. All empty instances will map -to a `Nothing`. +Used to transform a given [`First`][first] instance to a `Maybe` +instance, `firstToMaybe` will turn a non-empty instance into +a [`Just`](#just) wrapping the original value contained within +the [`First`][first]. All empty instances will map to a [`Nothing`](#nothing). Like all `crocks` transformation functions, `firstToMaybe` has two possible -signatures and will behave differently when passed either a `First` instance -or a function that returns an instance of `First`. When passed the instance, -a transformed `Maybe` is returned. When passed a `First` returning function, -a function will be returned that takes a given value and returns a `Maybe`. +signatures and will behave differently when passed either +a [`First`][first] instance or a function that returns an instance +of [`First`][first]. When passed the instance, a transformed `Maybe` is +returned. When passed a [`First`][first] returning function, a function will be +returned that takes a given value and returns a `Maybe`. ```javascript import Maybe from 'crocks/Maybe' @@ -1447,15 +1450,17 @@ lastToMaybe :: Last a -> Maybe a lastToMaybe :: (a -> Last b) -> a -> Maybe b ``` -Used to transform a given `Last` instance to a `Maybe` instance, `lastToMaybe` -will turn a non-empty instance into a `Just` wrapping the original value -contained within the `Last`. All empty instances will map to a `Nothing`. +Used to transform a given [`Last`][last] instance to a `Maybe` instance, +`lastToMaybe` will turn a non-empty instance into a [`Just`](#just) wrapping the +original value contained within the [`Last`][last]. All empty instances will map +to a [`Nothing`](#nothing). Like all `crocks` transformation functions, `lastToMaybe` has two possible -signatures and will behave differently when passed either a `Last` instance -or a function that returns an instance of `Last`. When passed the instance, -a transformed `Maybe` is returned. When passed a `Last` returning function, -a function will be returned that takes a given value and returns a `Maybe`. +signatures and will behave differently when passed either +a [`Last`][last] instance or a function that returns an instance +of [`Last`][last]. When passed the instance, a transformed `Maybe` is returned. +When passed a [`Last`][last] returning function, a function will be returned +that takes a given value and returns a `Maybe`. ```javascript import Maybe from 'crocks/Maybe' @@ -1500,11 +1505,11 @@ resultToMaybe :: (a -> Result e b) -> a -> Maybe b ``` Used to transform a given `Result` instance to a `Maybe` -instance, `resultToMaybe` will turn an `Ok` instance into a `Just` wrapping -the original value contained in the `Ok`. All `Err` instances will map to -a `Nothing`, mapping the originally contained value to a `Unit`. Values on the -`Err` will be lost and as such this transformation is considered lossy in -that regard. +instance, `resultToMaybe` will turn an `Ok` instance into +a [`Just`](#just) wrapping the original value contained in the `Ok`. +All `Err` instances will map to a [`Nothing`](#nothing), mapping the originally +contained value to a `Unit`. Values on the `Err` will be lost and as such this +transformation is considered lossy in that regard. Like all `crocks` transformation functions, `resultToMaybe` has two possible signatures and will behave differently when passed either an `Result` instance @@ -1550,4 +1555,9 @@ Just('so good') ``` -[pred]: ../Pred.html +[pred]: ./Pred.html +[either]: ./Either.html +[left]: ./Either.html#left +[right]: ./Either.html#right +[first]: ../monoids/First.html +[last]: ../monoids/Last.html diff --git a/docs/src/pages/docs/crocks/Pair.md b/docs/src/pages/docs/crocks/Pair.md index 4c0da349b..0b0377fc9 100644 --- a/docs/src/pages/docs/crocks/Pair.md +++ b/docs/src/pages/docs/crocks/Pair.md @@ -11,7 +11,7 @@ Pair a b ``` `Pair` allows the ability to represent two distinct values of different types. -Much like how `Either` is known as canonical Sum Type and defines the basis for +Much like how [`Either`][either] is known as canonical Sum Type and defines the basis for all other Sum Types that ship with `crocks`, `Pair` is known as the canonical Product Type and also at the heart of all Product Types in `crocks`. @@ -416,7 +416,8 @@ flow({ a: 10, b: 5 }) #### sequence ```haskell -Applicative TypeRep t, Apply f => Pair a (f b) ~> (t | (b -> f b)) -> f (Pair a b) +Apply f => Pair a (f b) ~> (c -> f c) -> f (Pair a b) +Applicative f => Pair a (f b) ~> TypeRep f -> f (Pair a b) ``` When an instance of `Pair` wraps an `Apply` instance in its second position, @@ -479,7 +480,8 @@ flow(pair) #### traverse ```haskell -Applicative TypeRep t, Apply f => Pair a b ~> ((t | (b -> f b)), (b -> f c)) -> f (Pair a c) +Apply f => Pair a b ~> (d -> f d), (b -> f c)) -> f (Pair a c) +Applicative f => Pair a b ~> (TypeRep f, (b -> f c)) -> f (Pair a c) ``` Used to apply the "effect" of an `Apply` to a value in the second position of @@ -579,8 +581,9 @@ Pair a b ~> ((a -> c), (b -> d)) -> Pair d c Used to map the value of a `Pair`s first position into the second position and the second position into the first, `swap` takes two functions as its arguments. The first function is used to map the value in the first position to the second, -while the second 'maps the second into the first'. If no mapping is required on -either side, then [`identity`][identity] functions can be used in one or both arguments. +while the second maps the second into the first. If no mapping is required on +either side, then [`identity`][identity] functions can be used in one or both +arguments. ```javascript import Pair from 'crocks/Pair' @@ -1001,3 +1004,4 @@ Pair(Sum.empty(), []) [fanout]: ../functions/helpers.html#fanout [frompairs]: ../functions/helpers.html#frompairs [identity]: ../functions/combinators.html#identity +[either]: ../crocks/Either.html diff --git a/docs/src/pages/docs/crocks/index.md b/docs/src/pages/docs/crocks/index.md index 16966c2c2..2034641ba 100644 --- a/docs/src/pages/docs/crocks/index.md +++ b/docs/src/pages/docs/crocks/index.md @@ -8,19 +8,19 @@ weight: 2 The `crocks` are the heart and soul of this library. This is where you will find all your favorite ADT's you have grown to love. They include gems such as: -[`Maybe`][maybe], `Either` and `IO`, to name a few. They are usually just a simple -constructor that takes either a function or value (depending on the type) -and will return you a "container" that wraps whatever you passed it. Each -container provides a variety of functions that act as the operations you can do -on the contained value. There are many types that share the same function names, -but what they do from type to type may vary. +[`Maybe`][maybe], [`Either`][either] and `IO`, to name a few. They are usually +just a simple constructor that takes either a function or value (depending on +the type) and will return you a "container" that wraps whatever you passed it. +Each container provides a variety of functions that act as the operations you +can do on the contained value. There are many types that share the same function +names, but what they do from type to type may vary. | Crock | Constructor | Instance | |---|:---|:---| | [`Arrow`][arrow] | [`id`][arrow-id] | [`both`][arrow-both], [`compose`][arrow-compose], [`contramap`][arrow-contra],[`first`][arrow-first], [`map`][arrow-map], [`promap`][arrow-promap], [`runWith`][arrow-runwith], [`second`][arrow-second] | | [`Async`][async] | [`Rejected`][async-rejected], [`Resolved`][async-resolved], [`all`][async-all], [`resolveAfter`][async-resolveAfter], [`rejectAfter`][async-rejectafter], [`fromNode`][async-fromnode], [`fromPromise`][async-frompromise], [`of`][async-of] | [`alt`][async-alt], [`ap`][async-ap], [`bimap`][async-bimap], [`chain`][async-chain], [`coalesce`][async-coalesce], [`race`][async-race], [`fork`][async-fork], [`map`][async-map], [`of`][async-of], [`swap`][async-swap], [`toPromise`][async-topromise] | | [`Const`][const] | -- | [`ap`][const-ap], [`chain`][const-chain], [`concat`][const-concat], [`equals`][const-equals], [`map`][const-map], [`valueOf`][const-valueof] | -| `Either` | `Left`, `Right`, `of`| `alt`, `ap`, `bimap`, `chain`, `coalesce`, `concat`, `either`, `equals`, `map`, `of`, `sequence`, `swap`, `traverse` | +| [`Either`][either] | [`Left`][either-left], [`Right`][either-right], [`of`][either-of]| [`alt`][either-alt], [`ap`][either-ap], [`bimap`][either-bimap], [`chain`][either-chain], [`coalesce`][either-coalesce], [`concat`][either-concat], [`either`][either-either], [`equals`][either-equals], [`map`][either-map], [`of`][either-of], [`sequence`][either-sequence], [`swap`][either-swap], [`traverse`][either-traverse] | | [`Equiv`][equiv] | [`empty`][equiv-empty] | [`concat`][equiv-concat], [`contramap`][equiv-contra], [`compareWith`][equiv-compare], [`valueOf`][equiv-value] | | `Identity` | `of` | `ap`, `chain`, `concat`, `equals`, `map`, `of`, `sequence`, `traverse`, `valueOf` | | `IO` | `of` | `ap`, `chain`, `map`, `of`, `run` | @@ -67,7 +67,6 @@ but what they do from type to type may vary. [async-race]: Async.html#race [async-fork]: Async.html#fork [async-map]: Async.html#map -[async-of]: Async.html#of [async-swap]: Async.html#swap [async-topromise]: Async.html#topromise @@ -79,6 +78,23 @@ but what they do from type to type may vary. [const-chain]: Const.html#chain [const-valueof]: Const.html#valueof +[either]: Either.html +[either-left]: Either.html#left +[either-right]: Either.html#right +[either-of]: Either.html#of +[either-alt]: Either.html#alt +[either-ap]: Either.html#ap +[either-bimap]: Either.html#bimap +[either-chain]: Either.html#chain +[either-coalesce]: Either.html#coalesce +[either-concat]: Either.html#concat +[either-either]: Either.html#either +[either-equals]: Either.html#equals +[either-map]: Either.html#map +[either-sequence]: Either.html#sequence +[either-swap]: Either.html#swap +[either-traverse]: Either.html#traverse + [equiv]: Equiv.html [equiv-empty]: Equiv.html#empty [equiv-concat]: Equiv.html#concat diff --git a/docs/src/pages/docs/functions/index.md b/docs/src/pages/docs/functions/index.md index 348bd3cb0..260d1b492 100644 --- a/docs/src/pages/docs/functions/index.md +++ b/docs/src/pages/docs/functions/index.md @@ -43,7 +43,7 @@ need to account for for the rest of your flow. | Function | Signature | Location | |:---|:---|:---| -| [`applyto`][applyto] | `a -> (a -> b) -> b` | `crocks/combinators/applyTo` | +| [`applyTo`][applyto] | `a -> (a -> b) -> b` | `crocks/combinators/applyTo` | | [`composeB`][composeb] | `(b -> c) -> (a -> b) -> a -> c` | `crocks/combinators/composeB` | | [`constant`][constant] | `a -> () -> a` | `crocks/combinators/constant` | | [`flip`][flip] | `(a -> b -> c) -> b -> a -> c` | `crocks/combinators/flip` | diff --git a/docs/src/pages/docs/functions/pointfree-functions.md b/docs/src/pages/docs/functions/pointfree-functions.md index 0fc7d64ba..5eab94f31 100644 --- a/docs/src/pages/docs/functions/pointfree-functions.md +++ b/docs/src/pages/docs/functions/pointfree-functions.md @@ -95,19 +95,19 @@ accepted Datatype): ##### Datatypes | Function | Datatypes | |---|:---| -| `alt` | [`Async`][async-alt], `Either`, [`Maybe`][maybe-alt], `Result` | -| `ap` | `Array`, [`Async`][async-ap], [`Const`][const-ap], `Either`, `Identity`, `IO`, `List`, [`Maybe`][maybe-ap], [`Pair`][pair-ap], [`Reader`][reader-ap], `Result`, [`State`][state-ap], `Unit`, `Writer` | -| `bimap` | [`Async`][async-bimap], `Either`, [`Pair`][pair-bimap], `Result` | +| `alt` | [`Async`][async-alt], [`Either`][either-alt], [`Maybe`][maybe-alt], `Result` | +| `ap` | `Array`, [`Async`][async-ap], [`Const`][const-ap], [`Either`][either-ap], `Identity`, `IO`, `List`, [`Maybe`][maybe-ap], [`Pair`][pair-ap], [`Reader`][reader-ap], `Result`, [`State`][state-ap], `Unit`, `Writer` | +| `bimap` | [`Async`][async-bimap], [`Either`][either-bimap], [`Pair`][pair-bimap], `Result` | | `both` | [`Arrow`][arrow-both], `Function`, `Star` | -| `chain` | `Array`, [`Async`][async-chain], [`Const`][const-chain], `Either`, `Identity`, `IO`, `List`, [`Maybe`][maybe-chain], [`Pair`][pair-chain], [`Reader`][reader-chain], `Result`, [`State`][state-chain], `Unit`, `Writer` | -| `coalesce` | [`Async`][async-coalesce], `Either`, [`Maybe`][maybe-coalesce], `Result` | +| `chain` | `Array`, [`Async`][async-chain], [`Const`][const-chain], [`Either`][either-chain], `Identity`, `IO`, `List`, [`Maybe`][maybe-chain], [`Pair`][pair-chain], [`Reader`][reader-chain], `Result`, [`State`][state-chain], `Unit`, `Writer` | +| `coalesce` | [`Async`][async-coalesce], [`Either`][either-coalesce], [`Maybe`][maybe-coalesce], `Result` | | `compareWith` | [`Equiv`][equiv-compare] | -| `concat` | [`All`][all-concat], [`Any`][any-concat], `Array`, [`Assign`][assign-concat], [`Const`][const-concat], `Either`, [`Endo`][endo-concat], [`Equiv`][equiv-concat], [`First`][first-concat], `Identity`, [`Last`][last-concat], `List`, [`Max`][max-concat], [`Maybe`][maybe-concat], [`Min`][min-concat], [`Pair`][pair-concat], [`Pred`][pred-concat], [`Prod`][prod-concat], `Result`, `String`, [`Sum`][sum-concat], [`Tuple`][tuple-concat], `Unit` | +| `concat` | [`All`][all-concat], [`Any`][any-concat], `Array`, [`Assign`][assign-concat], [`Const`][const-concat], [`Either`][either-concat], [`Endo`][endo-concat], [`Equiv`][equiv-concat], [`First`][first-concat], `Identity`, [`Last`][last-concat], `List`, [`Max`][max-concat], [`Maybe`][maybe-concat], [`Min`][min-concat], [`Pair`][pair-concat], [`Pred`][pred-concat], [`Prod`][prod-concat], `Result`, `String`, [`Sum`][sum-concat], [`Tuple`][tuple-concat], `Unit` | | `cons` | `Array`, `List` | | `contramap` | [`Arrow`][arrow-contra], [`Equiv`][equiv-contra], [`Pred`][pred-contra], `Star` | -| `either` | `Either`, [`Maybe`][maybe-either], `Result` | +| `either` | [`Either`][either-either], [`Maybe`][maybe-either], `Result` | | `empty` | [`All`][all-empty], [`Any`][any-empty], `Array`, [`Assign`][assign-empty], [`Endo`][endo-empty], [`Equiv`][equiv-empty], [`First`][first-empty], [`Last`][last-empty], `List`, [`Max`][max-empty], [`Min`][min-empty], `Object`, [`Pred`][pred-empty], [`Prod`][prod-empty], `String`, [`Sum`][sum-empty], `Unit` | -| `equals` | [`All`][all-equals], [`Any`][any-equals], `Array`, [`Assign`][assign-equals], `Boolean`, [`Const`][const-equals], `Either`, [`First`][first-equals], [`Last`][last-equals], `List`, [`Max`][max-equals], [`Maybe`][maybe-equals], [`Min`][min-equals], `Number`, `Object`, [`Pair`][pair-equals], [`Prod`][prod-equals], `Result`, `String`, [`Sum`][sum-equals], [`Tuple`][tuple-equals], `Unit`, `Writer` | +| `equals` | [`All`][all-equals], [`Any`][any-equals], `Array`, [`Assign`][assign-equals], `Boolean`, [`Const`][const-equals], [`Either`][either-equals], [`First`][first-equals], [`Last`][last-equals], `List`, [`Max`][max-equals], [`Maybe`][maybe-equals], [`Min`][min-equals], `Number`, `Object`, [`Pair`][pair-equals], [`Prod`][prod-equals], `Result`, `String`, [`Sum`][sum-equals], [`Tuple`][tuple-equals], `Unit`, `Writer` | | [`evalWith`][eval] | [`State`][state-eval] | | [`execWith`][exec] | [`State`][state-exec] | | `extend` | [`Pair`][pair-extend] | @@ -118,7 +118,7 @@ accepted Datatype): | [`fst`][fst] | [`Pair`][pair-fst] | | `head` | `Array`, `List`, `String` | | `log` | `Writer` | -| `map` | [`Async`][async-map], `Array`, [`Arrow`][arrow-map], [`Const`][const-map], `Either`, `Function`, `Identity`, `IO`, `List`, [`Maybe`][maybe-map], `Object`, [`Pair`][pair-map], [`Reader`][reader-map], `Result`, `Star`, [`State`][state-map], [`Tuple`][tuple-map], `Unit`, `Writer` | +| `map` | [`Async`][async-map], `Array`, [`Arrow`][arrow-map], [`Const`][const-map], [`Either`][either-map], `Function`, `Identity`, `IO`, `List`, [`Maybe`][maybe-map], `Object`, [`Pair`][pair-map], [`Reader`][reader-map], `Result`, `Star`, [`State`][state-map], [`Tuple`][tuple-map], `Unit`, `Writer` | | `merge` | [`Pair`][pair-merge], [`Tuple`][tuple-merge] | | `option` | [`First`][first-option], [`Last`][last-option], [`Maybe`][maybe-option] | | `promap` | [`Arrow`][arrow-pro], `Star` | @@ -130,11 +130,11 @@ accepted Datatype): | `run` | `IO` | | `runWith` | [`Arrow`][arrow-run], [`Endo`][endo-run], [`Pred`][pred-run], [`Reader`][reader-run], `Star`, [`State`][state-run] | | `second` | [`Arrow`][arrow-second], `Function`, `Star` | -| `sequence` | `Array`, `Either`, `Identity`, `List`, [`Maybe`][maybe-sequence], [`Pair`][pair-sequence], `Result` | +| `sequence` | `Array`, [`Either`][either-sequence], `Identity`, `List`, [`Maybe`][maybe-sequence], [`Pair`][pair-sequence], `Result` | | [`snd`][snd] | [`Pair`][pair-snd] | -| `swap` | [`Async`][async-swap], `Either`, [`Pair`][pair-swap], `Result` | +| `swap` | [`Async`][async-swap], [`Either`][either-swap], [`Pair`][pair-swap], `Result` | | `tail` | `Array`, `List`, `String` | -| `traverse` | `Array`, `Either`, `Identity`, `List`, [`Maybe`][maybe-traverse], [`Pair`][pair-traverse], `Result` | +| `traverse` | `Array`, [`Either`][either-traverse], `Identity`, `List`, [`Maybe`][maybe-traverse], [`Pair`][pair-traverse], `Result` | | `valueOf` | [`All`][all-value], [`Any`][any-value], [`Assign`][assign-value], [`Const`][const-value], [`Endo`][endo-value], [`Equiv`][equiv-value], [`First`][first-value], `Identity`, [`Last`][last-value], [`Max`][max-value], [`Min`][min-value], [`Pred`][pred-value], [`Prod`][prod-value], [`Sum`][sum-value], `Unit`, `Writer` | [all-concat]: ../monoids/All.html#concat @@ -181,6 +181,19 @@ accepted Datatype): [endo-run]: ../monoids/Endo.html#runwith [endo-value]: ../monoids/Endo.html#valueof +[either-alt]: ../crocks/Either.html#alt +[either-ap]: ../crocks/Either.html#ap +[either-bimap]: ../crocks/Either.html#bimap +[either-chain]: ../crocks/Either.html#chain +[either-coalesce]: ../crocks/Either.html#coalesce +[either-concat]: ../crocks/Either.html#concat +[either-either]: ../crocks/Either.html#either +[either-equals]: ../crocks/Either.html#equals +[either-map]: ../crocks/Either.html#map +[either-sequence]: ../crocks/Either.html#sequence +[either-swap]: ../crocks/Either.html#swap +[either-traverse]: ../crocks/Either.html#traverse + [equiv-compare]: ../crocks/Equiv.html#comparewith [equiv-concat]: ../crocks/Equiv.html#concat [equiv-contra]: ../crocks/Equiv.html#contramap diff --git a/docs/src/pages/docs/functions/transformation-functions.md b/docs/src/pages/docs/functions/transformation-functions.md index e95a335cb..6aaf9c204 100644 --- a/docs/src/pages/docs/functions/transformation-functions.md +++ b/docs/src/pages/docs/functions/transformation-functions.md @@ -70,14 +70,15 @@ unnested Not all types can be transformed to and from each other. Some of them are lazy and/or asynchronous, or are just too far removed. Also, some transformations -will result in a loss of information. Moving from an `Either` to a `Maybe`, for -instance, would lose the `Left` value of `Either` as a `Maybe`'s first parameter -(`Nothing`) is fixed at `Unit`. Conversely, if you move the other way around, -from a `Maybe` to an `Either` you must provide a default `Left` value. Which -means, if the inner `Maybe` results in a `Nothing`, it will map to `Left` of -your provided value. As such, not all of these functions are guaranteed -isomorphic. With some types you just cannot go back and forth and expect to -retain information. +will result in a loss of information. Moving from an [`Either`][either] to +a [`Maybe`][maybe], for instance, would lose the [`Left`][left] value +of [`Either`][either] as a [`Maybe`][maybe]'s first parameter +([`Nothing`][nothing]) is fixed at `Unit`. Conversely, if you move the other way +around, from a [`Maybe`][maybe] to an [`Either`][either] you must provide a +default [`Left`][left] value. Which means, if the inner [`Maybe`][maybe] results +in a [`Nothing`][nothing], it will map to [`Left`][left] of your provided value. +As such, not all of these functions are guaranteed isomorphic. With some types +you just cannot go back and forth and expect to retain information. Each function provides two signatures, one for if a Function is used for the second argument and another if the source ADT is passed instead. Although it may @@ -143,23 +144,23 @@ bad | [`eitherToMaybe`][either-maybe] | `Either b a -> Maybe a` | `(a -> Either c b) -> a -> Maybe b` | `crocks/Maybe` | | `eitherToResult` | `Either e a -> Result e a` | `(a -> Either e b) -> a -> Result e b` | `crocks/Result` | | [`firstToAsync`][first-async] | `e -> First a -> Async e a` | `e -> (a -> First b) -> a -> Async e b` | `crocks/Async` | -| `firstToEither` | `c -> First a -> Either c a` | `c -> (a -> First b) -> a -> Either c b` | `crocks/Either` | +| [`firstToEither`][first-either] | `c -> First a -> Either c a` | `c -> (a -> First b) -> a -> Either c b` | `crocks/Either` | | [`firstToLast`][first-last] | `First a -> Last a` | `(a -> First b) -> a -> Last b` | `crocks/Last` | | [`firstToMaybe`][first-maybe] | `First a -> Maybe a` | `(a -> First b) -> a -> Maybe b` | `crocks/Maybe` | | `firstToResult` | `c -> First a -> Result c a` | `c -> (a -> First b) -> a -> Result c b` | `crocks/Result` | | [`lastToAsync`][last-async] | `e -> Last a -> Async e a` | `e -> (a -> Last b) -> a -> Async e b` | `crocks/Async` | -| `lastToEither` | `c -> Last a -> Either c a` | `c -> (a -> Last b) -> a -> Either c b` | `crocks/Either` | +| [`lastToEither`][last-either] | `c -> Last a -> Either c a` | `c -> (a -> Last b) -> a -> Either c b` | `crocks/Either` | | [`lastToFirst`][last-first] | `Last a -> First a` | `(a -> Last b) -> a -> First b` | `crocks/First` | | [`lastToMaybe`][last-maybe] | `Last a -> Maybe a` | `(a -> Last b) -> a -> Maybe b` | `crocks/Maybe` | | `lastToResult` | `c -> Last a -> Result c a` | `c -> (a -> Last b) -> a -> Result c b` | `crocks/Result` | | `listToArray` | `List a -> [ a ]` | `(a -> List b) -> a -> [ b ]` | `crocks/List` | | [`maybeToAsync`][maybe-async] | `e -> Maybe a -> Async e a` | `e -> (a -> Maybe b) -> a -> Async e b` | `crocks/Async` | -| `maybeToEither` | `c -> Maybe a -> Either c a` | `c -> (a -> Maybe b) -> a -> Either c b` | `crocks/Either` | +| [`maybeToEither`][maybe-either] | `c -> Maybe a -> Either c a` | `c -> (a -> Maybe b) -> a -> Either c b` | `crocks/Either` | | [`maybeToFirst`][maybe-first] | `Maybe a -> First a` | `(a -> Maybe b) -> a -> First b` | `crocks/First` | | [`maybeToLast`][maybe-last] | `Maybe a -> Last a` | `(a -> Maybe b) -> a -> Last b` | `crocks/Last` | | `maybeToResult` | `c -> Maybe a -> Result c a` | `c -> (a -> Maybe b) -> a -> Result c b` | `crocks/Result` | | [`resultToAsync`][result-async] | `Result e a -> Async e a` | `(a -> Result e b) -> a -> Async e b` | `crocks/Async` | -| `resultToEither` | `Result e a -> Either e a` | `(a -> Result e b) -> a -> Either e b` | `crocks/Either` | +| [`resultToEither`][result-either] | `Result e a -> Either e a` | `(a -> Result e b) -> a -> Either e b` | `crocks/Either` | | [`resultToFirst`][result-first] | `Result e a -> First a` | `(a -> Result e b) -> a -> First b` | `crocks/First` | | [`resultToLast`][result-last] | `Result e a -> Last a` | `(a -> Result e b) -> a -> Last b` | `crocks/Last` | | [`resultToMaybe`][result-maybe] | `Result e a -> Maybe a` | `(a -> Result e b) -> a -> Maybe b` | `crocks/Maybe` | @@ -171,6 +172,11 @@ bad [maybe-async]: ../crocks/Async.html#maybetoasync [result-async]: ../crocks/Async.html#resulttoasync +[first-either]: ../crocks/Either.html#firsttoeither +[last-either]: ../crocks/Either.html#lasttoeither +[maybe-either]: ../crocks/Either.html#maybetoeither +[result-either]: ../crocks/Either.html#resulttoeither + [either-maybe]: ../crocks/Maybe.html#eithertomaybe [first-maybe]: ../crocks/Maybe.html#firsttomaybe [last-maybe]: ../crocks/Maybe.html#lasttomaybe @@ -185,3 +191,8 @@ bad [first-last]: ../monoids/Last.html#firsttolast [maybe-last]: ../monoids/Last.html#maybetolast [result-last]: ../monoids/Last.html#resulttolast + +[maybe]: ../crocks/Maybe.html +[nothing]: ../crocks/Maybe.html#nothing +[either]: ../crocks/Either.html +[left]: ../crocks/Either.html#left diff --git a/docs/src/pages/docs/monoids/First.md b/docs/src/pages/docs/monoids/First.md index 284513f19..c008a7093 100644 --- a/docs/src/pages/docs/monoids/First.md +++ b/docs/src/pages/docs/monoids/First.md @@ -10,7 +10,7 @@ First a = First (Maybe a) ``` `First` is a `Monoid` that will always return the first, non-empty value when -(2) `First` instances are combined. `First` is able to be a `Monoid` because +two `First` instances are combined. `First` is able to be a `Monoid` because it implements a [`Maybe`][maybe] under the hood. The use of the [`Maybe`][maybe] allows for an [`empty`](#empty) `First` to be represented with a [`Nothing`][nothing]. @@ -148,7 +148,7 @@ empty() First a ~> b -> Boolean ``` -Used to compare the underlying values of (2) `First` instances for equality by +Used to compare the underlying values of two `First` instances for equality by value, `equals` takes any given argument and returns `true` if the passed arguments is a `First` with an underlying value equal to the underlying value of the `First` the method is being called on. If the passed argument is not @@ -186,7 +186,7 @@ First(95) First a ~> First a -> First a ``` -`concat` is used to combine (2) `Semigroup`s of the same type under an operation +`concat` is used to combine two `Semigroup`s of the same type under an operation specified by the `Semigroup`. In the case of `First`, it will always provide the first non-empty value. Any subsequent non-empty values will be thrown away and will always result in the first non-empty value. @@ -321,18 +321,20 @@ eitherToFirst :: Either b a -> First a eitherToFirst :: (a -> Either c b) -> a -> First b ``` -Used to transform a given `Either` instance to a `First` -instance, `eitherToFirst` will turn a `Right` instance into a non-empty `First`, -wrapping the original value contained in the `Right`. All `Left` instances will -map to an [`empty`](#empty) `First`, mapping the originally contained value to a `Unit`. -Values on the `Left` will be lost and as such this transformation is considered -lossy in that regard. - -Like all `crocks` transformation functions, `eitherToFirst` has (2) possible -signatures and will behave differently when passed either an `Either` instance -or a function that returns an instance of `Either`. When passed the instance, -a transformed `First` is returned. When passed an `Either` returning function, -a function will be returned that takes a given value and returns a `First`. +Used to transform a given [`Either`][either] instance to a `First` +instance, `eitherToFirst` will turn a [`Right`][right] instance into a +non-empty `First`, wrapping the original value contained in +the [`Right`][right]. All [`Left`][left] instances will map to +an [`empty`](#empty) `First`, mapping the originally contained value to +a `Unit`. Values on the [`Left`][left] will be lost and as such this +transformation is considered lossy in that regard. + +Like all `crocks` transformation functions, `eitherToFirst` has two possible +signatures and will behave differently when passed either +an [`Either`][either] instance or a function that returns an instance +of [`Either`][either]. When passed the instance, a transformed `First` is +returned. When passed an [`Either`][either] returning function, a function will +be returned that takes a given value and returns a `First`. ```javascript import First from 'crocks/First' @@ -385,16 +387,17 @@ lastToFirst :: Last a -> First a lastToFirst :: (a -> Last b) -> a -> First b ``` -Used to transform a given `Last` instance to a `First` instance, `lastToFirst` -will turn a non-empty instance into a non-empty `First` wrapping the original -value contained within the `Last`. All [`empty`](#empty) instances will map -to an [`empty`](#empty) `First`. +Used to transform a given [`Last`][last] instance to a `First` instance, +`lastToFirst` will turn a non-empty instance into a non-empty `First` wrapping +the original value contained within the [`Last`][last]. +All [`empty`](#empty) instances will map to an [`empty`](#empty) `First`. -Like all `crocks` transformation functions, `lastToFirst` has (2) possible -signatures and will behave differently when passed either a `Last` instance -or a function that returns an instance of `Last`. When passed the instance, -a transformed `First` is returned. When passed a `Last` returning function, -a function will be returned that takes a given value and returns a `First`. +Like all `crocks` transformation functions, `lastToFirst` has two possible +signatures and will behave differently when passed either +a [`Last`][last] instance or a function that returns an instance +of [`Last`][last]. When passed the instance, a transformed `First` is returned. +When passed a [`Last`][last] returning function, a function will be returned +that takes a given value and returns a `First`. ```javascript import First from 'crocks/First' @@ -448,7 +451,7 @@ take a `Maybe` as its argument during construction. So while there is not a real need for this to be used for transforming instances, it can come in handy for lifting [`Maybe`][maybe] returning functions. -Like all `crocks` transformation functions, `maybeToFirst` has (2) possible +Like all `crocks` transformation functions, `maybeToFirst` has two possible signatures and will behave differently when passed either a [`Maybe`][maybe] instance or a function that returns an instance of [`Maybe`][maybe]. When passed the instance, a transformed `First` is returned. When passed @@ -519,7 +522,7 @@ to an [`empty`](#empty) `First`, mapping the originally contained value to a `Unit`. Values on the `Err` will be lost and as such this transformation is considered lossy in that regard. -Like all `crocks` transformation functions, `resultToFirst` has (2) possible +Like all `crocks` transformation functions, `resultToFirst` has two possible signatures and will behave differently when passed either an `Result` instance or a function that returns an instance of `Result`. When passed the instance, a transformed `First` is returned. When passed a `Result` returning function, @@ -568,3 +571,7 @@ firstNum(null) [maybe]: ../crocks/Maybe.html [nothing]: ../crocks/Maybe.html#nothing [option]: ../crocks/Maybe.html#option +[last]: ./Last.html +[either]: ../crocks/Either.html +[left]: ../crocks/Either.html#left +[right]: ../crocks/Either.html#right diff --git a/docs/src/pages/docs/monoids/Last.md b/docs/src/pages/docs/monoids/Last.md index 705cc1003..e4a8012c4 100644 --- a/docs/src/pages/docs/monoids/Last.md +++ b/docs/src/pages/docs/monoids/Last.md @@ -10,7 +10,7 @@ Last a = Last (Maybe a) ``` `Last` is a `Monoid` that will always return the last, non-empty value when -(2) `Last` instances are combined. `Last` is able to be a `Monoid` because +two `Last` instances are combined. `Last` is able to be a `Monoid` because it implements a [`Maybe`][maybe] under the hood. The use of the [`Maybe`][maybe] allows for an [`empty`](#empty) `Last` to be represented with a `Nothing`. @@ -145,7 +145,7 @@ empty() Last a ~> b -> Boolean ``` -Used to compare the underlying values of (2) `Last` instances for equality by +Used to compare the underlying values of two `Last` instances for equality by value, `equals` takes any given argument and returns `true` if the passed argument is a `Last` with an underlying value equal to the underlying value of the `Last` the method is being called on. If the passed argument is not @@ -183,7 +183,7 @@ Last(95) Last a ~> Last a -> Last a ``` -`concat` is used to combine (2) `Semigroup`s of the same type under an operation +`concat` is used to combine two `Semigroup`s of the same type under an operation specified by the `Semigroup`. In the case of `Last`, it will always provide the last non-empty value. All previous non-empty values will be thrown away and will always result in the last non-empty value. @@ -317,17 +317,17 @@ eitherToLast :: Either b a -> Last a eitherToLast :: (a -> Either c b) -> a -> Last b ``` -Used to transform a given `Either` instance to a `Last` -instance, `eitherToLast` will turn a `Right` instance into a non-empty `Last`, -wrapping the original value contained in the `Right`. All `Left` instances will +Used to transform a given [`Either`][either] instance to a `Last` +instance, `eitherToLast` will turn a [`Right`][right] instance into a non-empty `Last`, +wrapping the original value contained in the [`Right`][right]. All [`Left`][left] instances will map to an [`empty`](#empty) `Last`, mapping the originally contained value to -a `Unit`. Values on the `Left` will be lost and as such this transformation is +a `Unit`. Values on the [`Left`][left] will be lost and as such this transformation is considered lossy in that regard. -Like all `crocks` transformation functions, `eitherToLast` has (2) possible -signatures and will behave differently when passed either an `Either` instance -or a function that returns an instance of `Either`. When passed the instance, -a transformed `Last` is returned. When passed an `Either` returning function, +Like all `crocks` transformation functions, `eitherToLast` has two possible +signatures and will behave differently when passed either an [`Either`][either] instance +or a function that returns an instance of [`Either`][either]. When passed the instance, +a transformed `Last` is returned. When passed an [`Either`][either] returning function, a function will be returned that takes a given value and returns a `Last`. ```javascript @@ -381,16 +381,18 @@ firstToLast :: First a -> Last a firstToLast :: (a -> First b) -> a -> Last b ``` -Used to transform a given `First` instance to a `Last` instance, `firstToLast` -will turn a non-empty instance into a non-empty `Last` wrapping the original -value contained within the `First`. All [`empty`](#empty) instances will map -to an [`empty`](#empty) `Last`. +Used to transform a given [`First`][first] instance to +a `Last` instance, `firstToLast` will turn a non-empty instance into a +non-empty `Last` wrapping the original value contained within +the [`First`][first]. All [`empty`](#empty) instances will map to +an [`empty`](#empty) `Last`. -Like all `crocks` transformation functions, `firstToLast` has (2) possible -signatures and will behave differently when passed either a `First` instance -or a function that returns an instance of `First`. When passed the instance, -a transformed `Last` is returned. When passed a `First` returning function, -a function will be returned that takes a given value and returns a `Last`. +Like all `crocks` transformation functions, `firstToLast` has two possible +signatures and will behave differently when passed either +a [`First`][first] instance or a function that returns an instance +of [`First`][first]. When passed the instance, a transformed `Last` is returned. +When passed a [`First`][first] returning function, a function will be returned +that takes a given value and returns a `Last`. ```javascript import Last from 'crocks/Last' @@ -446,7 +448,7 @@ take a [`Maybe`][maybe] as its argument during construction. So while there is n real need for this to be used for transforming instances, it can come in handy for lifting [`Maybe`][maybe] returning functions. -Like all `crocks` transformation functions, `maybeToLast` has (2) possible +Like all `crocks` transformation functions, `maybeToLast` has two possible signatures and will behave differently when passed either a [`Maybe`][maybe] instance or a function that returns an instance of [`Maybe`][maybe]. When passed the instance, a transformed `Last` is returned. When passed a [`Maybe`][maybe] returning function, @@ -516,7 +518,7 @@ to an [`empty`](#empty) `Last`, mapping the originally contained value to a `Unit`. Values on the `Err` will be lost and as such this transformation is considered lossy in that regard. -Like all `crocks` transformation functions, `resultToLast` has (2) possible +Like all `crocks` transformation functions, `resultToLast` has two possible signatures and will behave differently when passed either an `Result` instance or a function that returns an instance of `Result`. When passed the instance, a transformed `Last` is returned. When passed a `Result` returning function, @@ -565,3 +567,7 @@ lastNum(null) [maybe]: ../crocks/Maybe.html [nothing]: ../crocks/Maybe.html#nothing [option]: ../crocks/Maybe.html#option +[first]: ./First.html +[either]: ../crocks/Either.html +[left]: ../crocks/Either.html#left +[right]: ../crocks/Either.html#right