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

Data that can be folded over to change its structure by altering or combining elements.

Unlike Witchcraft.Functorss, the end result will not respect the original structure unless you build it back up manually.

examples

Examples

iex> right_fold([1, 2, 3], 0, &+/2) # sum
6

properties

Properties

People are working on Foldable properties. This is one of the exceptions to there needing to conform to properties. In the meantime, we are testing that naturality is preserved, which is be a free theorm.

If that fails, something is very wrong with the instance.

type-class

Type Class

An instance of Witchcraft.Foldable define Witchcraft.Foldable.right_fold/3.

Foldable   [right_fold/3]

Link to this section Summary

Functions

Check if a foldable is full of only trues

The same as all?/1, but with a custom predicate matcher

Check if a foldable contains any trues

The same as all?/1, but with a custom predicate matcher

Check if a foldable data structure is empty

Lift a function over a foldable structure generating lists of results, and then concatenate the resulting lists

Concatenate all lists in a foldable structure

Combine all elements using monoidal append

Map a functional over all elements and fold them together

The same as left_fold/3, but uses the first element as the seed

Left-associative fold over a structure to alter the structure and/or reduce it to a single summary value.

Count the number of elements in a foldable structure

Find the maximum element in a foldable structure using the default ordering from Witchcraft.Ord.

Find the maximum element in a foldable structure using a custom comparitor

Check if a foldable structure contains a particular element

Find the minimum element in a foldable structure using the default ordering from Witchcraft.Ord.

Find the maximum element in a foldable structure using a custom comparitor

Test whether the structure is empty. The default implementation is optimized for structures that are similar to lists, because there is no general way to do better.

Product of all numbers in a foldable

Get a random element from a foldable structure.

The same as right_fold/3, but uses the first element as the seed

Right-associative fold over a structure to alter the structure and/or reduce it to a single summary value. The right-association makes it possible to cease computation on infinite streams of data.

Sum all numbers in a foldable

Run each action from left to right, discarding all values.

The same as then_traverse, but with the arguments flipped.

traverse actions over data, but ignore the results.

Turn any Foldable into a List

Link to this section Types

Link to this section Functions

@spec all?(t()) :: boolean()

Check if a foldable is full of only trues

examples

Examples

iex> all?([true, true, false])
false

iex> all?({true, true, false})
false

%BinaryTree{
  left:  true,
  right: %BinaryTree{
    left:  true,
    right: false
  }
} |> all?()
#=> false
Link to this function

all?(foldable, predicate)

View Source
@spec all?(t(), (any() -> boolean())) :: boolean()

The same as all?/1, but with a custom predicate matcher

examples

Examples

iex> import Integer
iex> all?([1, 2, 3], &is_odd/1)
false

%BinaryTree{
  left:  1,
  right: %BinaryTree{
    left:  2,
    right: 3
  }
}
|> all?(&Integer.is_odd?/1)
#=> false
@spec any?(t()) :: boolean()

Check if a foldable contains any trues

examples

Examples

iex> any? [true, true, false]
true

%BinaryTree{
  left:  true,
  right: %BinaryTree{
    left:  true,
    right: false
  }
} |> any?()
#=> true

Not that the Tuple instance behaves somewhat conterintuitively

iex> any? {true, true, false}
false

iex> any? {true, false, true}
true
Link to this function

any?(foldable, predicate)

View Source
@spec any?(t(), (any() -> boolean())) :: boolean()

The same as all?/1, but with a custom predicate matcher

examples

Examples

iex> require Integer
iex> any?([1, 2, 3], &Integer.is_odd/1)
true

%BinaryTree{
  left:  1,
  right: %BinaryTree{
    left:  2,
    right: 3
  }
}
|> any(&Integer.is_odd?/1)
#=> true

See Witchcraft.Foldable.length/1.

@spec empty?(t()) :: boolean()

Check if a foldable data structure is empty

examples

Examples

iex> empty?("")
true

iex> empty?("hi")
false

iex> empty?(%{})
true
Link to this function

flat_map(foldable, mapper)

View Source
@spec flat_map(t(), (any() -> [any()])) :: [any()]

Lift a function over a foldable structure generating lists of results, and then concatenate the resulting lists

examples

Examples

iex> flat_map([1, 2, 3, 4, 5, 6], fn x -> [x, x] end)
[1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6]

iex> flat_map({1, 2, 3, 4, 5, 6}, fn x -> [x, x] end)
[6, 6]

%BinaryTree{
  left:  1,
  right: %BinaryTree{
    left:  2,
    right: 3
  }
}
|> flat_map(fn x -> [x, x] end)
#=> [1, 1, 2, 2, 3, 3]
Link to this function

flatten(contained_lists)

View Source
@spec flatten(t()) :: [any()]

Concatenate all lists in a foldable structure

examples

Examples

iex> flatten([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
[1, 2, 3, 4, 5, 6, 7, 8, 9]

iex> flatten({[1, 2, 3], [4, 5, 6], [7, 8, 9]})
[7, 8, 9]

%BinaryTree{
  left:  [1, 2, 3],
  right: %BinaryTree{
    left:  [4, 5],
    right: [6]
  }
}
|> flatten()
#=> [1, 2, 3, 4, 5, 6]
@spec fold(t()) :: any()

Combine all elements using monoidal append

examples

Examples

iex> fold([1, 2, 3])
6

iex> fold([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
[1, 2, 3, 4, 5, 6, 7, 8, 9]
@spec fold_map(t(), (... -> any())) :: any()

Map a functional over all elements and fold them together

examples

Examples

iex> fold_map([1, 2, 3], fn x -> [x, x * 10] end)
[1, 10, 2, 20, 3, 30]

iex> fold_map([[1, 2, 3], [4, 5, 6], [7, 8, 9]], fn x -> [x, x] end)
[
  [1, 2, 3], [1, 2, 3],
  [4, 5, 6], [4, 5, 6],
  [7, 8, 9], [7, 8, 9]
]
Link to this function

left_fold(foldable, folder)

View Source
@spec left_fold(t(), (any(), any() -> any())) :: any()

The same as left_fold/3, but uses the first element as the seed

examples

Examples

iex> left_fold([1, 2, 3], &+/2)
6

iex> left_fold([100, 2, 5], &//2)
10.0 # ((100 / 2) / 5)

iex> left_fold([1, 2, 3], [], fn(acc, x) -> [x | acc] end)
[3, 2, 1]

Note the reducer argument order versus right_fold/2

iex> right_fold([100, 20, 10], &//2)
200.0

iex> left_fold([100, 20, 10], &//2)
0.5
Link to this function

left_fold(foldable, seed, folder)

View Source
@spec left_fold(t(), any(), (any(), any() -> any())) :: any()

Left-associative fold over a structure to alter the structure and/or reduce it to a single summary value.

The folder must be a binary function, with the second argument being the accumulated value thus far.

examples

Examples

iex> sum = fn xs -> right_fold(xs, 0, &+/2) end
iex> sum.([1, 2, 3])
6
iex> sum.([4, 5, 6])
15

iex> left_fold([1, 2, 3], [], fn(acc, x) -> [x | acc] end)
[3, 2, 1]

iex> left_fold({1, 2, 3}, [], fn(acc, x) -> [x | acc] end)
[3]

iex> left_fold([1, 2, 3], [4, 5, 6], fn(acc, x) -> [x | acc] end)
[3, 2, 1, 4, 5, 6]

Note the reducer argument order versus right_fold/3

iex> right_fold([1, 2, 3], [], fn(acc, x) -> [acc | x] end)
[1, 2, 3]

iex> left_fold([1, 2, 3], [], fn(acc, x) -> [acc | x] end)
[[[[] | 1] | 2] | 3]
@spec length(t()) :: non_neg_integer()

Count the number of elements in a foldable structure

examples

Examples

iex> use Witchcraft.Foldable
iex> length(%{})
0
iex> length(%{a: 1, b: 2})
2
iex> length("ࠀabc")
4
Link to this function

max(foldable_comparable)

View Source
@spec max(t()) :: Witchcraft.Ord.t()

Find the maximum element in a foldable structure using the default ordering from Witchcraft.Ord.

Elements must implement Witchcraft.Ord.

examples

Examples

iex> use Witchcraft.Foldable
iex> max([2, 3, 1])
3
iex> max([[4], [1, 2, 3, 4]])
[4]

%BinaryTree{
  node: 1,
  left: %BinaryTree{
    node: 3
    left: 4
  },
  right: 2
}
|> max()
#=> 4
@spec max(t(), [{:by, (any(), any() -> Witchcraft.Ord.ordering())}]) ::
  Witchcraft.Ord.t()

Find the maximum element in a foldable structure using a custom comparitor

Elements must implement Witchcraft.Ord.

Comes in both a safe and unsafe(!) version

examples

Examples

iex> use Witchcraft.Foldable
...> [1, 2, 7]
...> |> max(by: fn(x, y) ->
...>   x
...>   |> Integer.mod(3)
...>   |> Witchcraft.Ord.compare(Integer.mod(y, 3))
...> end)
2
@spec member?(t(), any()) :: boolean()

Check if a foldable structure contains a particular element

examples

Examples

iex> member?([1, 2, 3], 2)
true

iex> member?([1, 2, 3], 99)
false

iex> member?(%{a: 1, b: 2}, 2)
true

iex> member?(%{a: 1, b: 2}, 99)
false

Find the minimum element in a foldable structure using the default ordering from Witchcraft.Ord.

Elements must implement Witchcraft.Ord.

examples

Examples

iex> use Witchcraft.Foldable
iex> min([2, 3, 1])
1
iex> min([[4], [1, 2, 3, 4]])
[1, 2, 3, 4]

%BinaryTree{
  node: 4,
  left: %BinaryTree{
    node: 3
    left: 1
  },
  right: 2
}
|> min()
#=> 1
@spec min(t(), [{:by, (any(), any() -> Witchcraft.Ord.t())}]) :: any()

Find the maximum element in a foldable structure using a custom comparitor

Elements must implement Witchcraft.Ord.

Comes in both a safe and unsafe(!) version

examples

Examples

iex> use Witchcraft.Foldable
...> [8, 2, 1]
...> |> min(by: fn(x, y) ->
...>   x
...>   |> Integer.mod(4)
...>   |> Witchcraft.Ord.compare(Integer.mod(y, 4))
...> end)
8
@spec null?(t()) :: boolean()

Test whether the structure is empty. The default implementation is optimized for structures that are similar to lists, because there is no general way to do better.

examples

Examples

iex> null?([])
true

iex> null?([1, 2, 3])
false
@spec product(t()) :: number()

Product of all numbers in a foldable

examples

Examples

iex> product([1, 2, 3])
6

iex> product({1, 2, 3})
6

%BinaryTree{
  left:  4,
  right: %BinaryTree{
    left: 2,
    right: 10
  }
}
|> product()
#=> 80
@spec random(t()) :: any() | Witchcraft.Foldable.EmptyError.t()

Get a random element from a foldable structure.

examples

Examples

random([1, 2, 3])
#=> 1

random([1, 2, 3])
#=> 3

random(%BinaryTree{left: %Empty{}, node: 2, right: %BinaryTree{node: 1}})
1
Link to this function

right_fold(foldable, folder)

View Source
@spec right_fold(t(), (... -> any())) :: any()

The same as right_fold/3, but uses the first element as the seed

examples

Examples

iex> right_fold([1, 2, 3], &+/2)
6

iex> right_fold([100, 2, 5], &//2)
40.0 # (2 / (5 / 100))

iex> right_fold([[], 1, 2, 3], fn(x, acc) -> [x | acc] end)
[1, 2, 3]
Link to this function

right_fold(foldable, seed, folder)

View Source
@spec right_fold(t(), any(), (any(), any() -> any())) :: any()

Right-associative fold over a structure to alter the structure and/or reduce it to a single summary value. The right-association makes it possible to cease computation on infinite streams of data.

The folder must be a binary function, with the second argument being the accumulated value thus far.

examples

Examples

iex> sum = fn xs -> right_fold(xs, 0, &+/2) end
iex> sum.([1, 2, 3])
6
iex> sum.([4, 5, 6])
15

See Witchcraft.Foldable.length/1.

@spec sum(t()) :: number()

Sum all numbers in a foldable

examples

Examples

iex> sum([1, 2, 3])
6

iex> sum({1, 2, 3})
3

%BinaryTree{
  left:  4,
  right: %BinaryTree{
    left: 2,
    right: 10
  }
} |> sum()
#=> 16
Link to this function

then_sequence(foldable_monad)

View Source
@spec then_sequence(t()) :: Witchcraft.Monad.t()

Run each action from left to right, discarding all values.

Always returns %Witchcraft.Unit{} in the same foldbale structure that you started with.

examples

Examples

iex> then_sequence([[1, 2, 3], [4, 5, 6]])
[
  %Witchcraft.Unit{},
  %Witchcraft.Unit{},
  %Witchcraft.Unit{},
  %Witchcraft.Unit{},
  %Witchcraft.Unit{},
  %Witchcraft.Unit{},
  %Witchcraft.Unit{},
  %Witchcraft.Unit{},
  %Witchcraft.Unit{}
]

iex> then_sequence({{1, 2, 3}, {4, 5, 6}})
{4, 5, %Witchcraft.Unit{}}

iex> then_sequence({[1, 2, 3], [4, 5, 6]})
[
  %Witchcraft.Unit{},
  %Witchcraft.Unit{},
  %Witchcraft.Unit{}
]
Link to this function

then_through(fun, traversable)

View Source
@spec then_through(Witchcraft.Apply.fun(), t()) :: Witchcraft.Apply.t()

The same as then_traverse, but with the arguments flipped.

examples

Examples

iex> fn x -> [x, x * 5, x * 10] end
...> |> then_through([1, 2, 3])
[
    #
    %Witchcraft.Unit{}, %Witchcraft.Unit{}, %Witchcraft.Unit{},
    %Witchcraft.Unit{}, %Witchcraft.Unit{}, %Witchcraft.Unit{},
    %Witchcraft.Unit{}, %Witchcraft.Unit{}, %Witchcraft.Unit{},
    #
    %Witchcraft.Unit{}, %Witchcraft.Unit{}, %Witchcraft.Unit{},
    %Witchcraft.Unit{}, %Witchcraft.Unit{}, %Witchcraft.Unit{},
    %Witchcraft.Unit{}, %Witchcraft.Unit{}, %Witchcraft.Unit{},
    #
    %Witchcraft.Unit{}, %Witchcraft.Unit{}, %Witchcraft.Unit{},
    %Witchcraft.Unit{}, %Witchcraft.Unit{}, %Witchcraft.Unit{},
    %Witchcraft.Unit{}, %Witchcraft.Unit{}, %Witchcraft.Unit{}
]
Link to this function

then_traverse(foldable, fun)

View Source
@spec then_traverse(t(), Witchcraft.Apply.fun()) :: Witchcraft.Apply.t()

traverse actions over data, but ignore the results.

Not a typo: this is in the correct module, since it doens't depend directly on Witchcraft.Traversable, but behaves in a similar manner.

examples

Examples

iex> [1, 2, 3]
...> |> then_traverse(fn x -> [x, x * 5, x * 10] end)
[
    #
    %Witchcraft.Unit{}, %Witchcraft.Unit{}, %Witchcraft.Unit{},
    %Witchcraft.Unit{}, %Witchcraft.Unit{}, %Witchcraft.Unit{},
    %Witchcraft.Unit{}, %Witchcraft.Unit{}, %Witchcraft.Unit{},
    #
    %Witchcraft.Unit{}, %Witchcraft.Unit{}, %Witchcraft.Unit{},
    %Witchcraft.Unit{}, %Witchcraft.Unit{}, %Witchcraft.Unit{},
    %Witchcraft.Unit{}, %Witchcraft.Unit{}, %Witchcraft.Unit{},
    #
    %Witchcraft.Unit{}, %Witchcraft.Unit{}, %Witchcraft.Unit{},
    %Witchcraft.Unit{}, %Witchcraft.Unit{}, %Witchcraft.Unit{},
    %Witchcraft.Unit{}, %Witchcraft.Unit{}, %Witchcraft.Unit{}
]
@spec to_list(t()) :: [any()]

Turn any Foldable into a List

example

Example

iex> to_list({1, 2, 3})
[1, 2, 3]

iex> to_list(%{a: 1, b: 2, c: 3})
[1, 2, 3]