Skip to main content

karpal_core/
alternative.rs

1// Copyright (C) 2026 Industrial Algebra
2// SPDX-License-Identifier: Apache-2.0
3
4use crate::applicative::Applicative;
5use crate::plus::Plus;
6
7/// Alternative: Applicative + Plus with no extra methods (blanket impl).
8///
9/// Laws:
10/// - Distributivity: `ap(alt(f, g), x) == alt(ap(f, x), ap(g, x))`
11/// - Annihilation: `ap(zero(), x) == zero()`
12pub trait Alternative: Applicative + Plus {}
13
14impl<F: Applicative + Plus> Alternative for F {}
15
16#[cfg(test)]
17mod law_tests {
18    use crate::alt::Alt;
19    use crate::apply::Apply;
20    use crate::hkt::OptionF;
21    use crate::plus::Plus;
22    use proptest::prelude::*;
23
24    proptest! {
25        // Distributivity: ap(alt(f, g), x) == alt(ap(f, x), ap(g, x))
26        #[test]
27        fn option_distributivity(x in any::<i16>()) {
28            let f: Option<fn(i16) -> i16> = Some(|a| a.wrapping_add(1));
29            let g: Option<fn(i16) -> i16> = Some(|a| a.wrapping_mul(2));
30
31            let left = OptionF::ap(OptionF::alt(f, g), Some(x));
32            let right = OptionF::alt(OptionF::ap(f, Some(x)), OptionF::ap(g, Some(x)));
33            prop_assert_eq!(left, right);
34        }
35
36        // Annihilation: ap(zero(), x) == zero()
37        #[test]
38        fn option_annihilation(x in any::<Option<i32>>()) {
39            let left = OptionF::ap(OptionF::zero::<fn(i32) -> i32>(), x);
40            let right: Option<i32> = OptionF::zero();
41            prop_assert_eq!(left, right);
42        }
43    }
44}