Skip to content

Commit

Permalink
Documentation for Identity (#330)
Browse files Browse the repository at this point in the history
The commit for the `Identity` documentation for #42
  • Loading branch information
dalefrancis88 authored Oct 29, 2018
1 parent 4ab96f5 commit 6f16346
Show file tree
Hide file tree
Showing 4 changed files with 356 additions and 3 deletions.
342 changes: 342 additions & 0 deletions docs/src/pages/docs/crocks/Identity.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,342 @@
---
title: "Identity"
description: "Identity Crock"
layout: "guide"
weight: 60
---

```haskell
Identity a
```

`Identity` is a `crock` that can be used to wrap a common interface around
existing Javascript types and functions. It maintains integrity by lifting
and applying functions and types as is, without adding any additional structure
or effects. By not applying and additional structure to existing functions,
`Identity` can be swapped in and out for other `Functor`s that do apply their
own structure and effects.

```javascript
import Identity from 'crocks/Identity'

Identity(10)
//=> Identity 10
```
<article id="topic-implements">

## Implements
`Setoid`, `Semigroup`, `Functor`, `Traversable`, `Apply`, `Chain`, `Applicative`, `Monad`

</article>

<article id="topic-construction">

## Construction

```haskell
Identity :: a -> Identity a
```

The contstructor for an `Identity` is a unary function. When a value is passed
in an `Identity` of the given value is returned ready for `map` or `chain`.

```javascript
import Identity from 'crocks/Identity'

const fromComputerCode = String.fromCharCode

Identity(42)
.map(fromComputerCode)
//=> Identity '*'
```

</article>

<article id="topic-constructor">

## Constructor Methods

#### of

```haskell
Identity.of :: a -> Identity a
```

`of` is used to construct an `Identity` with any given value. It is there to
allow `Identity` to work as a pointed functor.

```javascript
import Identity from 'crocks/Identity'

Identity.of(42)
//=> Identity 42

Identity.of(true)
//=> Identity true
```

</article>

<article id="topic-instance">

## Instance Methods

#### equals

```haskell
Identity a ~> b -> Boolean
```

Used to compare the underlying values of two `Identity` instances for equality by
value, `equals` takes any given argument and returns `true` if the passed
arguments is an `Identity` with an underlying value equal to the underlying value
of the `Identity` the method is being called on. If the passed argument is not
an `Identity` or the underlying values are not equal, `equals` will return `false`.

```javascript
import Identity from 'crocks/Identity'

import equals from 'crocks/pointfree/equals'

Identity(33)
.equals(Identity(33))
//=> true

Identity(33)
.equals(Identity('33'))
//=> false

// by value, not reference for most types
Identity({ a: 86, b: true })
.equals(Identity({ a: 86, b: true }))
//=> true

equals(Identity(95), 95)
//=> false

equals(Identity([ 2, 3 ]), Identity([ 2, 3 ]))
//=> true
```

#### concat

```haskell
Identity s => Identity s ~> Identity s -> Identity s
```

When an underlying value of a given `Identity` is fixed to a `Semigroup`,
`concat` can be used to concat another `Identity` instance with an underlying
`Semigroup` of the same type. Expecting an `Identity` wrapping a `Semigroup` of
the same type, `concat` will give back a new `Identity` instance wrapping the
result of combining the two underlying `Semigroup`s.

```javascript
import Identity from 'crocks/Identity'

import Sum from 'crocks/Sum'

import compose from 'crocks/helpers/compose'
import concat from 'crocks/pointfree/concat'
import flip from 'crocks/combinators/flip'
import map from 'crocks/pointfree/map'
import mapReduce from 'crocks/helpers/mapReduce'
import valueOf from 'crocks/pointfree/valueOf'

// empty :: Identity Sum
const empty =
Identity(Sum.empty())

// sumList :: [ * ] -> Identity Number
const sumList = compose(
map(valueOf),
mapReduce(compose(Identity, Sum), flip(concat), empty)
)

Identity([ 34 ])
.concat(Identity([ 92 ]))
//=> Identity [ 34, 92 ]

sumList([ 3, 4, 5 ])
//=> Identity 12
```

#### map

```haskell
Identity a ~> (a -> b) -> Identity b
```

Used to apply transformations to values you've lifted into an `Identity`, `map`
takes a function that it will lift into the context of the `Identity` and apply
to it the wrapped value. `Identity` contains no behavior and will do nothing
more than apply the value inside the `Identity` to the function.

```javascript
import Identity from 'crocks/Identity'
import map from 'crocks/pointfree/map'

const prod = a => b => a * b

const mapDouble = map(prod(2))

mapDouble(Identity(5))
//=> Identity 10
```

#### ap

```haskell
Identity (a -> b) ~> Identity a -> Identity b
```

`ap` allows for values wrapped in an `Identity` to be applied to functions also
wrapped in an `Identity`. In order to use `ap`, the `Identity` must contain a
function as its value. Under the hood, `ap` unwraps both the function
and the value to be applied and applies the value to the function. Finally it
will wrap the result of that application back into an `Identity`. It is required
that the inner function is curried.

```javascript
import Identity from 'crocks/Identity'

const prod = a => b => a * b
const double = prod(2)

Identity(double)
.ap(5)
//=> Identity 10
```

#### sequence

```haskell
Apply f => Identity (f a) ~> (b -> f b) -> f (Identity a)
Applicative f => Identity (f a) ~> TypeRep f -> f (Identity a)
```

When an instance of `Identity` wraps an `Apply` instance, `sequence` can be used to
swap the type sequence. `sequence` requires either an `Applicative TypeRep` or
an `Apply` returning function to be provided for its argument.

`sequence` can be derived from [`traverse`](#traverse) by passing it an
`identity` function (`x => x`).

```javascript
import Identity from 'crocks/Identity'

import Maybe from 'crocks/Maybe'
import sequence from 'crocks/pointfree/sequence'

// seqId :: Identity Maybe a -> Maybe Identity a
const seqMaybe =
sequence(Maybe)

seqMaybe(Identity(Maybe(42)))
//=> Just Identity 42
```

#### traverse

```haskell
Apply f => Identity a ~> (a -> f b) -> f (Identity b)
Applicative f => Identity a ~> (TypeRep f, (a -> f b)) -> f (Identity a b)
```

Used to apply the "effect" of an `Apply` to a value inside of a `Identity`,
`traverse` combines both the "effects" of the `Apply` and the `Identity` by
returning a new instance of the `Apply`, wrapping the result of the
`Apply`s "effect" on the value in the `Identity`.

`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 `Identity`. Both arguments must provide
an instance of the target `Apply`.

```javascript
import Identity from 'crocks/Identity'
import IO from 'crocks/IO'

import compose from 'crocks/helpers/compose'
import isNumber from 'crocks/predicates/isNumber'
import traverse from 'crocks/pointfree/traverse'
import ifElse from 'crocks/logic/ifElse'

// someGlobal :: Number
let someGlobal = 10

// addToGlobal :: Number -> IO Number
const addToGlobal = x => IO(() => someGlobal + x)

// safeAddToGlobal :: a -> IO (Maybe Number)
const safeAddToGlobal = compose(
traverse(IO, addToGlobal),
Identity,
ifElse(isNumber, x => x, () => NaN)
)

safeAddToGlobal(32)
.run()
//=> Identity 42
//someGlobal => 42

safeAddToGlobal(32)
.run()
.valueOf()
//=> 42

safeAddToGlobal(undefined)
.run()
.valueOf()
//=> NaN
```

#### chain

```haskell
Identity a ~> (a -> Identity b) -> Identity b
```

Normally one of the ways `Monad`s like `Identity` are able to be combined and
have their effects applied is through `chain`. However `Identity` is different
because there are no effects to apply. `chain` will simply take a function that
returns `Identity` and applies it to its value.

```javascript
import Identity from 'crocks/Identity'
import compose from 'crocks/helpers/compose'
import chain from 'crocks/pointfree/chain'

const prod = a => b => a * b
const doubleAsIdentity = compose(Identity, prod(2))

doubleAsIdentity(21)
//=> Identity 42

chain(doubleAsIdentity, Identity(5))
//=> Identity 10
```

#### valueOf

```haskell
Identity a ~> () -> a
```

`valueOf` is used as a means of extraction. This function is used primarily for
convenience for some of the helper functions that ship with `crocks`. Calling
`valueOf` on an `Identity` instance will return the value being contained.

```javascript
import Identity from 'crocks/Identity'

Identity(42)
.valueOf()
//=> 33

Identity(20)
.concat(Identity(22))
.valueOf()
//=> 35
```

</article>
1 change: 0 additions & 1 deletion docs/src/pages/docs/crocks/Maybe.md
Original file line number Diff line number Diff line change
Expand Up @@ -730,7 +730,6 @@ safeAddToGlobal(32)
safeAddToGlobal(undefined)
.run()
//=> Nothing
//someGlobal => 42
```

#### chain
Expand Down
2 changes: 1 addition & 1 deletion docs/src/pages/docs/crocks/Pair.md
Original file line number Diff line number Diff line change
Expand Up @@ -480,7 +480,7 @@ flow(pair)
#### traverse

```haskell
Apply f => Pair a b ~> (d -> f d), (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)
```

Expand Down
14 changes: 13 additions & 1 deletion docs/src/pages/docs/crocks/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ names, but what they do from type to type may vary.
| [`Const`][const] | [`empty`][const-empty], [`of`][const-of] | [`ap`][const-ap], [`concat`][const-concat], [`empty`][const-empty], [`equals`][const-equals], [`map`][const-map], [`of`][const-of], [`valueOf`][const-valueof] |
| [`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` |
| [`Identity`][identity] | [`of`][identity-of] | [`ap`][identity-ap], [`chain`][identity-chain], [`concat`][identity-concat], [`equals`][identity-equals], [`map`][identity-map], [`of`][identity-of], [`sequence`][identity-sequence], [`traverse`][identity-traverse], [`valueOf`][identity-valueof] |
| `IO` | `of` | `ap`, `chain`, `map`, `of`, `run` |
| `List` | `empty`, `fromArray`, `of` | `ap`, `chain`, `concat`, `cons`, `empty`, `equals`, `filter`, `fold`, `foldMap`, `head`, `map`, `of`, `reduce`, `reduceRight`, `reject`, `sequence`, `tail`, `toArray`, `traverse`, `valueOf` |
| [`Maybe`][maybe] | [`Nothing`][maybe-nothing], [`Just`][maybe-just], [`of`][maybe-of], [`zero`][maybe-zero] | [`alt`][maybe-alt], [`ap`][maybe-ap], [`chain`][maybe-chain], [`coalesce`][maybe-coalesce], [`concat`][maybe-concat], [`equals`][maybe-equals], [`either`][maybe-either], [`map`][maybe-map], [`of`][maybe-of], [`option`][maybe-option], [`sequence`][maybe-sequence], [`traverse`][maybe-traverse], [`zero`][maybe-zero] |
Expand Down Expand Up @@ -96,6 +96,18 @@ names, but what they do from type to type may vary.
[either-swap]: Either.html#swap
[either-traverse]: Either.html#traverse

[identity]: Identity.html
[identity-of]: Identity.html#of
[identity-alt]: Identity.html#alt
[identity-ap]: Identity.html#ap
[identity-chain]: Identity.html#chain
[identity-concat]: Identity.html#concat
[identity-equals]: Identity.html#equals
[identity-map]: Identity.html#map
[identity-sequence]: Identity.html#sequence
[identity-traverse]: Identity.html#traverse
[identity-valueof]: Identity.html#valueof

[equiv]: Equiv.html
[equiv-empty]: Equiv.html#empty
[equiv-concat]: Equiv.html#concat
Expand Down

0 comments on commit 6f16346

Please sign in to comment.