Skip to main content

karpal_arrow/
arrow_choice.rs

1// Copyright (C) 2026 Industrial Algebra
2// SPDX-License-Identifier: Apache-2.0
3
4use crate::arrow::Arrow;
5
6/// ArrowChoice: an Arrow that can route through sum types.
7///
8/// Uses `Result<L, R>` as the sum type, consistent with karpal-profunctor's Choice.
9///
10/// Laws:
11/// - left(arr(f)) == arr(|r| r.map(f))
12/// - left(compose(f, g)) == compose(left(f), left(g))
13/// - compose(arr(Ok), f) == compose(left(f), arr(Ok))
14pub trait ArrowChoice: Arrow {
15    /// Route the Ok branch through the arrow, passing Err through.
16    fn left<A: Clone + 'static, B: Clone + 'static, C: Clone + 'static>(
17        pab: Self::P<A, B>,
18    ) -> Self::P<Result<A, C>, Result<B, C>>;
19
20    /// Route the Err branch through the arrow, passing Ok through.
21    fn right<A: Clone + 'static, B: Clone + 'static, C: Clone + 'static>(
22        pab: Self::P<A, B>,
23    ) -> Self::P<Result<C, A>, Result<C, B>> {
24        let mirror_in = Self::arr(|r: Result<C, A>| match r {
25            Ok(c) => Err(c),
26            Err(a) => Ok(a),
27        });
28        let mirror_out = Self::arr(|r: Result<B, C>| match r {
29            Ok(b) => Err(b),
30            Err(c) => Ok(c),
31        });
32        Self::compose(mirror_out, Self::compose(Self::left(pab), mirror_in))
33    }
34
35    /// `+++`: apply f on Ok, g on Err.
36    fn splat<A: Clone + 'static, B: Clone + 'static, C: Clone + 'static, D: Clone + 'static>(
37        f: Self::P<A, B>,
38        g: Self::P<C, D>,
39    ) -> Self::P<Result<A, C>, Result<B, D>> {
40        Self::compose(Self::right(g), Self::left(f))
41    }
42
43    /// `|||`: merge two arrows, one for each branch of Result.
44    fn fanin<A: Clone + 'static, B: Clone + 'static, C: Clone + 'static>(
45        f: Self::P<A, C>,
46        g: Self::P<B, C>,
47    ) -> Self::P<Result<A, B>, C> {
48        let merge = Self::arr(|r: Result<C, C>| match r {
49            Ok(c) | Err(c) => c,
50        });
51        Self::compose(merge, Self::splat(f, g))
52    }
53}