# Witchcraft.Chain (Witchcraft v1.0.4) View Source

Chain function applications on contained data that may have some additional effect

As a diagram:

`%Container<data> --- (data -> %Container<updated_data>) ---> %Container<updated_data>`

## Examples

```
iex> chain([1, 2, 3], fn x -> [x, x] end)
[1, 1, 2, 2, 3, 3]
alias Algae.Maybe.{Nothing, Just}
%Just{just: 42} >>> fn x -> %Just{just: x + 1} end
#=> %Just{just: 43}
%Just{just: 42}
>>> fn x -> if x > 50, do: %Just{just: x + 1}, else: %Nothing{} end
>>> fn y -> y * 100 end
#=> %Nothing{}
```

## Type Class

An instance of `Witchcraft.Chain`

must also implement `Witchcraft.Apply`

,
and define `Witchcraft.Chain.chain/2`

.

```
Functor [map/2]
↓
Apply [convey/2]
↓
Chain [chain/2]
```

# Link to this section Summary

## Functions

Operator alias for `draw/2`

Operator alias for `chain/2`

.

An alias for `chain/2`

.

`do`

notation sugar

Sequentially compose actions, piping values through successive function chains.

Compose link functions to create a new link function.

`chain/2`

but with the arguments flipped.

Join together one nested level of a data structure that contains itself

Compose link functions to create a new link function.

# Link to this section Types

## Specs

## Specs

t() :: any()

# Link to this section Functions

## Specs

Operator alias for `draw/2`

Extends the `<~`

/ `<<~`

heirarchy with one more level of power / abstraction

## Examples

```
iex> to_monad = fn x -> (fn _ -> x end) end
...> bound = to_monad.(&(&1 + 10)) <<< to_monad.(&(&1 * 10))
...> bound.(10)
20
```

In Haskell, this is the famous `=<<`

operator, but Elixir doesn't allow that
infix operator.

## Specs

Operator alias for `chain/2`

.

Extends the `~>`

/ `~>>`

heirarchy with one more level of power / abstraction

## Examples

```
iex> to_monad = fn x -> (fn _ -> x end) end
...> bound = to_monad.(&(&1 * 10)) >>> to_monad.(&(&1 + 10))
...> bound.(10)
20
```

In Haskell, this is the famous `>>=`

operator, but Elixir doesn't allow that
infix operator.

## Specs

An alias for `chain/2`

.

Provided as a convenience for those coming from other languages.

`do`

notation sugar

Sequences chainable actions. Note that each line must be of the same type.

For a version with `return`

, please see `Witchcraft.Monad.monad/2`

## Examples

```
iex> chain do
...> [1]
...> end
[1]
iex> chain do
...> [1, 2, 3]
...> [4, 5, 6]
...> [7, 8, 9]
...> end
[
7, 8, 9,
7, 8, 9,
7, 8, 9,
7, 8, 9,
7, 8, 9,
7, 8, 9,
7, 8, 9,
7, 8, 9,
7, 8, 9
]
iex> chain do
...> a <- [1, 2, 3]
...> b <- [4, 5, 6]
...> [a * b]
...> end
[
4, 5, 6,
8, 10, 12,
12, 15, 18
]
```

Normal functions are fine within the `do`

as well, as long as each line
ends up being the same chainable type

```
iex> import Witchcraft.{Functor, Applicative}
...> chain do
...> map([1, 2, 3], fn x -> x + 1 end)
...> of([], 42)
...> [7, 8, 9] ~> fn x -> x * 10 end
...> end
[
70, 80, 90,
70, 80, 90,
70, 80, 90
]
```

Or with a custom type

```
alias Algae.Maybe.{Nothing, Just}
chain do
%Just{just: 4}
%Just{just: 5}
%Just{just: 6}
end
#=> %Just{just: 6}
chain do
%Just{just: 4}
%Nothing{}
%Just{just: 6}
end
#=> %Nothing{}
```

##
`let`

bindings

`let`

s allow you to hold static or intermediate values inside a
do-block, much like normal assignment

```
iex> chain do
...> let a = 4
...> [a]
...> end
[4]
iex> chain do
...> a <- [1, 2]
...> b <- [3, 4]
...> let [h | _] = [a * b]
...> [h, h, h]
...> end
[3, 3, 3, 4, 4, 4, 6, 6, 6, 8, 8, 8]
```

## Desugaring

### Sequencing

The most basic form

```
chain do
[1, 2, 3]
[4, 5, 6]
[7, 8, 9]
end
```

is equivalent to

```
[1, 2, 3]
|> then([4, 5, 6])
|> then([7, 8, 9])
```

###
`<-`

("drawn from")

Drawing values from within a chainable structure is similar feels similar to assignmet, but it is pulling each value separately in a chain link function.

For instance

```
iex> chain do
...> a <- [1, 2, 3]
...> b <- [4, 5, 6]
...> [a * b]
...> end
[4, 5, 6, 8, 10, 12, 12, 15, 18]
```

desugars to this

```
iex> [1, 2, 3] >>> fn a ->
...> [4, 5, 6] >>> fn b ->
...> [a * b]
...> end
...> end
[4, 5, 6, 8, 10, 12, 12, 15, 18]
```

but is often much cleaner to read in do-notation, as it cleans up all of the nested functions (especially when the chain is very long).

You can also use values recursively:

```
# iex> chain do
# ...> a <- [1, 2, 3]
# ...> b <- [a, a * 10, a * 100]
# ...> [a + 1, b + 1]
# ...> end
# [
# 2, 2, 2, 11, 2, 101,
# 3, 3, 3, 21, 3, 201,
# 4, 4, 4, 31, 4, 301
# ]
```

## Specs

Sequentially compose actions, piping values through successive function chains.

The applied linking function must be unary and return data in the same type of container as the input. The chain function essentially "unwraps" a contained value, applies a linking function that returns the initial (wrapped) type, and collects them into a flat(ter) structure.

`chain/2`

is sometimes called "flat map", since it can also
be expressed as `data |> map(link_fun) |> flatten()`

.

As a diagram:

`%Container<data> --- (data -> %Container<updated_data>) ---> %Container<updated_data>`

## Examples

```
iex> chain([1, 2, 3], fn x -> [x, x] end)
[1, 1, 2, 2, 3, 3]
iex> [1, 2, 3]
...> |> chain(fn x -> [x, x] end)
...> |> chain(fn y -> [y, 2 * y, 3 * y] end)
[1, 2, 3, 1, 2, 3, 2, 4, 6, 2, 4, 6, 3, 6, 9, 3, 6, 9]
iex> chain([1, 2, 3], fn x ->
...> chain([x + 1], fn y ->
...> chain([y + 2, y + 10], fn z ->
...> [x, y, z]
...> end)
...> end)
...> end)
[1, 2, 4, 1, 2, 12, 2, 3, 5, 2, 3, 13, 3, 4, 6, 3, 4, 14]
```

## Specs

Compose link functions to create a new link function.

Note that this runs the same direction as `<|>`

("the math way").

This is `pipe_compose_link/2`

with arguments flipped.

## Examples

```
iex> links =
...> fn x -> [x, x] end
...> |> compose_link(fn y -> [y * 10] end)
...> |> compose_link(fn z -> [z + 42] end)
...>
...> [1, 2, 3] >>> links
[430, 430, 440, 440, 450, 450]
```

## Specs

`chain/2`

but with the arguments flipped.

## Examples

```
iex> draw(fn x -> [x, x] end, [1, 2, 3])
[1, 1, 2, 2, 3, 3]
iex> (fn y -> [y * 5, y * 10] end)
...> |> draw((fn x -> [x, x] end)
...> |> draw([1, 2, 3])) # note the "extra" closing paren
[5, 10, 5, 10, 10, 20, 10, 20, 15, 30, 15, 30]
```

## Specs

## Specs

Join together one nested level of a data structure that contains itself

## Examples

```
iex> join([[1, 2, 3]])
[1, 2, 3]
iex> join([[1, 2, 3], [4, 5, 6]])
[1, 2, 3, 4, 5, 6]
iex> join([[[1, 2, 3], [4, 5, 6]]])
[[1, 2, 3], [4, 5, 6]]
alias Algae.Maybe.{Nothing, Just}
%Just{
just: %Just{
just: 42
}
} |> join()
#=> %Just{just: 42}
join %Just{just: %Nothing{}}
#=> %Nothing{}
join %Just{just: %Just{just: %Nothing{}}}
#=> %Just{just: %Nothing{}}
%Nothing{} |> join() |> join() |> join() # ...and so on, forever
#=> %Nothing{}
```

Joining tuples is a bit counterintuitive, as it requires a very specific format:

```
iex> join { # Outer 2-tuple
...> {1, 2}, # Inner 2-tuple
...> {
...> {3, 4}, # Doubly inner 2-tuple
...> {5, 6, 7}
...> }
...> }
{{4, 6}, {5, 6, 7}}
iex> join {
...> {"a", "b"},
...> {
...> {"!", "?"},
...> {:ok, 123}
...> }
...> }
{{"a!", "b?"}, {:ok, 123}}
```

## Specs

Compose link functions to create a new link function.

This is `compose_link/2`

with arguments flipped.

## Examples

```
iex> links =
...> fn x -> [x, x] end
...> |> pipe_compose_link(fn y -> [y * 10] end)
...> |> pipe_compose_link(fn z -> [z + 42] end)
...>
...> [1, 2, 3] >>> links
[52, 52, 62, 62, 72, 72]
```