View Source Witchcraft.Arrow (Witchcraft v1.0.6-doma)
Arrows abstract the idea of computations, potentially with a context.
Arrows are in fact an abstraction above monads, and can be used both to express all other type classes in Witchcraft. They also enable some nice flow-based reasoning about computation.
For a nice illustrated explination, see Haskell/Understanding arrows
Arrows let you think diagrammatically, and is a powerful way of thinking about flow programming, concurrency, and more.
┌---> f --------------------------┐
| v
input ---> split unsplit ---> result
| ^
| ┌--- h ---┐ |
| | v |
└---> g ---> split unsplit ---┘
| ^
└--- i ---┘
type-class
Type Class
An instance of Witchcraft.Arrow
must also implement Witchcraft.Category
,
and define Witchcraft.Arrow.arrowize/2
.
Semigroupoid [compose/2, apply/2]
↓
Category [identity/1]
↓
Arrow [arrowize/2]
Link to this section Summary
Functions
Lift a function into an arrow, much like how of/2
does with data.
Alias for product/2
, meant to invoke a spacial metaphor.
Duplicate incoming data into both halves of a 2-tuple, and run one function on the left copy, and a different function on the right copy.
Target the first element of a tuple.
The identity function lifted into an arrow of the correct type.
Compose an arrow (left) with a function (right) to produce a new arrow.
Compose a function (left) with an arrow (right) to produce a new arrow.
Take two arguments (as a 2-tuple), and run one function on the left side (first element), and run a different function on the right side (second element).
Switch the associativity of a nested tuple. Helpful since many arrows act on a subset of a tuple, and you may want to move portions in and out of that stream.
Target the second element of a tuple.
Copy a single value into both positions of a 2-tuple.
Swap positions of elements in a tuple.
Merge two tuple values with a combining function.
Link to this section Types
@type t() :: (... -> any())
Link to this section Functions
Operator alias for fanout/2
.
examples
Examples
iex> fanned = fn x -> x - 10 end &&& fn y -> inspect(y) <> "!" end
...> fanned.(42)
{32, "42!"}
iex> fanned =
...> fn x -> x - 10 end
...> &&& fn y -> inspect(y) <> "!" end
...> &&& fn z -> inspect(z) <> "?" end
...> &&& fn d -> inspect(d) <> inspect(d) end
...> &&& fn e -> e / 2 end
...>
...> fanned.(42)
{{{{32, "42!"}, "42?"}, "4242"}, 21.0}
Lift a function into an arrow, much like how of/2
does with data.
Essentially a label for composing functions end-to-end, where instances may have their own special idea of what composition means. The simplest example is a regular function. Others are possible, such as Kleisli arrows.
examples
Examples
iex> use Witchcraft.Arrow
...> times_ten = arrowize(fn -> nil end, &(&1 * 10))
...> 5 |> pipe(times_ten)
50
Alias for product/2
, meant to invoke a spacial metaphor.
examples
Examples
iex> beside(&(&1 - 10), &(&1 <> "!")).({42, "Hi"})
{32, "Hi!"}
Duplicate incoming data into both halves of a 2-tuple, and run one function on the left copy, and a different function on the right copy.
┌------> f.(a) = x ------┐
| v
a ---> split = {a, a} {x, y}
| ^
└------> g.(a) = y ------┘
examples
Examples
iex> Witchcraft.Semigroupoid.pipe(42, fanout(&(&1 - 10), &(inspect(&1) <> "!")))
{32, "42!"}
Target the first element of a tuple.
examples
Examples
iex> first(fn x -> x * 50 end).({1, 1})
{50, 1}
The identity function lifted into an arrow of the correct type.
examples
Examples
iex> id_arrow(fn -> nil end).(99)
99
Compose an arrow (left) with a function (right) to produce a new arrow.
examples
Examples
iex> f = postcompose(
...> arrowize(fn _ -> nil end, fn x -> x + 1 end),
...> fn y -> y * 10 end
...> )
...> f.(42)
430
Compose a function (left) with an arrow (right) to produce a new arrow.
examples
Examples
iex> f = precompose(
...> fn x -> x + 1 end,
...> arrowize(fn _ -> nil end, fn y -> y * 10 end)
...> )
...> f.(42)
430
Take two arguments (as a 2-tuple), and run one function on the left side (first element), and run a different function on the right side (second element).
┌------> f.(a) = x -------┐
| v
{a, b} {x, y}
| ^
└------> g.(b) = y -------┘
examples
Examples
iex> product(&(&1 - 10), &(&1 <> "!")).({42, "Hi"})
{32, "Hi!"}
@spec reassociate({any(), {any(), any()}} | {{any(), any()}, any()}) :: {{any(), any()}, any()} | {any(), {any(), any()}}
Switch the associativity of a nested tuple. Helpful since many arrows act on a subset of a tuple, and you may want to move portions in and out of that stream.
examples
Examples
iex> reassociate({1, {2, 3}})
{{1, 2}, 3}
iex> reassociate({{1, 2}, 3})
{1, {2, 3}}
Target the second element of a tuple.
examples
Examples
iex> second(fn x -> x * 50 end).({1, 1})
{1, 50}
Copy a single value into both positions of a 2-tuple.
This is useful is you want to run functions on the input separately.
examples
Examples
iex> split(42)
{42, 42}
iex> import Witchcraft.Semigroupoid, only: [<~>: 2]
...> 5
...> |> split()
...> |> (second(fn x -> x - 2 end)
...> <~> first(fn y -> y * 10 end)
...> <~> second(&inspect/1)).()
{50, "3"}
iex> use Witchcraft.Arrow
...> 5
...> |> split()
...> |> pipe(second(fn x -> x - 2 end))
...> |> pipe(first(fn y -> y * 10 end))
...> |> pipe(second(&inspect/1))
{50, "3"}
Swap positions of elements in a tuple.
examples
Examples
iex> swap({1, 2})
{2, 1}
Merge two tuple values with a combining function.
examples
Examples
iex> unsplit({1, 2}, &+/2)
3