View Source Witchcraft.Bifunctor (Witchcraft v1.0.6-doma)

Similar to Witchcraft.Functor, but able to map two functions over two separate portions of some data structure (some product type).

Especially helpful when you need different hebaviours on different fields.

type-class

Type Class

An instance of Witchcraft.Bifunctor must also implement Witchcraft.Functor, and define Witchcraft.Apply.ap/2.

 Functor   [map/2]
    
Bifunctor  [bimap/2]

Link to this section Summary

Functions

The same as bimap/3, but with the functions curried

map separate fuctions over two fields in a product type.

The same as map_first, but with a curried function

The same as map_second, but with a curried function

map a function over the first value only

map a function over the second value only

Link to this section Types

Link to this section Functions

@spec bilift(t(), (... -> any()), (... -> any())) :: t()

The same as bimap/3, but with the functions curried

examples

Examples

iex> {:ok, 2, "hi"}
...> |> bilift(&*/2, &<>/2)
...> |> bimap(fn f -> f.(9) end, fn g -> g.("?!") end)
{:ok, 18, "hi?!"}
@spec bimap(t(), (any() -> any()), (any() -> any())) :: t()

map separate fuctions over two fields in a product type.

The order of fields doesn't always matter in the map. The first/second function application is determined by the instance. It also does not have to map all fields in a product type.

diagram

Diagram

          ------------------------------------
                                              |
%Combo{a: 5, b: :ok, c: "hello"} |> bimap(&(&1 * 100), &String.upcase/1)
                                                             |
                            ---------------------------------
#=> %Combo{a: 500, b: :ok, c: "HELLO"}

examples

Examples

iex> {1, "a"} |> bimap(&(&1 * 100), &(&1 <> "!"))
{100, "a!"}

iex> {:msg, 42, "number is below 50"}
...> |> bimap(&(%{subject: &1}), &String.upcase/1)
{:msg, %{subject: 42}, "NUMBER IS BELOW 50"}
@spec lift_first(t(), (... -> any())) :: t()

The same as map_first, but with a curried function

examples

Examples

iex> {:ok, 2, "hi"}
...> |> lift_first(&*/2)
...> |> map_first(fn f -> f.(9) end)
{:ok, 18, "hi"}
@spec lift_second(t(), (... -> any())) :: t()

The same as map_second, but with a curried function

examples

Examples

iex> {:ok, 2, "hi"}
...> |> lift_second(&<>/2)
...> |> map_second(fn f -> f.("?!") end)
{:ok, 2, "hi?!"}
@spec map_first(t(), (any() -> any())) :: t()

map a function over the first value only

examples

Examples

iex> {:ok, 2, "hi"} |> map_first(&(&1 * 100))
{:ok, 200, "hi"}
@spec map_second(t(), (any() -> any())) :: t()

map a function over the second value only

examples

Examples

iex> {:ok, 2, "hi"} |> map_second(&(&1 <> "!?"))
{:ok, 2, "hi!?"}