1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
/*
* SPDX-License-Identifier: MIT
* Copyright (c) 2023 - 2026. The DeepCausality Authors and Contributors. All Rights Reserved.
*/
use crate::;
/// Turning a structure inside out along the **diagonal**: the i-th slot of each inner container
/// meets the i-th slot of every other.
///
/// [`Traversable::sequence`](crate::Traversable::sequence) already flips `F<M<A>>` into `M<F<A>>`,
/// and for many `M` it is the operation wanted. It is not this one. `sequence` is bounded on
/// `M: Applicative`, and an applicative that also carries [`Monad`](crate::Monad) owes the
/// coherence law `apply(ff, fa) == bind(ff, |f| fmap(fa, f))`, which forces the **cartesian**
/// reading: every element against every element. Flipping a 2×2 structure whose four slots each
/// hold 50 values that way gives `50^4` results — every combination of the four — rather than 50.
///
/// When the inner containers are parallel runs of the same length, the cartesian product is not
/// what the caller means. Value *i* of one belongs with value *i* of the others; the pairing is by
/// index. That reading is [`Semigroupal::zip_with`], and this trait is `sequence` driven by it.
///
/// # Why it needs its own trait, and its own argument
///
/// A witness whose `zip` is positional cannot carry [`Pure`](crate::Pure). The unit of a positional
/// zip is the value that pairs with every slot of any container at any length — the infinite repeat
/// — and a finite carrier cannot represent it; `crate::lax_monoidal` sets out why inventing one
/// fails the unit laws at every value rather than in a corner. So the zip witnesses implement
/// [`Semigroupal`] and stop, and cannot drive `sequence`:
///
/// ```text
/// error[E0277]: the trait bound `ZipTensorWitness: Applicative<ZipTensorWitness>` is not satisfied
/// ```
///
/// With no `Pure` there is nothing to build a starting accumulator from, so the caller supplies
/// one. That is where the missing unit surfaces, and it is honest rather than a wart: the length
/// of the result is a decision the caller is making, and here they make it in the open.