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
/*
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/.
 */

//! The Alternative typeclass.

use crate::prelude::*;

/// Alternative typeclass for picking a successful result out of two fallible operations.
pub trait Alternative<A: Clone>: Applicative<A> {
    /// Fucking pain in the ass redundancy. This has to be in this trait to avoid potential spooky action at a distance e.g. by redefining a separate Hkt later.
    type Alternative<B: Clone>: Alternative<B, Alternative<A> = Self>;
    /// Value representing failure/emptiness/nothingness.
    #[must_use]
    fn empty() -> Self;
    /// Return a successful result if we have one.
    #[must_use]
    fn either<F: FnOnce() -> Self>(self, make_other: F) -> Self;
    /// Return empty or a trivial value based on a predicate.
    #[inline(always)]
    #[must_use]
    fn guard(b: bool) -> Self::Alternative<()>
    where
        Self::Alternative<()>: Applicative<(), Applicative<()> = Self::Alternative<()>>,
    {
        if b {
            consume::<Self::Alternative<()>, ()>(())
        } else {
            empty()
        }
    }
}

/// Value representing failure/emptiness/nothingness.
#[inline(always)]
#[must_use]
pub fn empty<AA: Alternative<A>, A: Clone>() -> AA {
    AA::empty()
}

/// Return a successful result if we have one.
#[inline(always)]
#[must_use]
pub fn either<AA: Alternative<A>, A: Clone, F: FnOnce() -> AA>(f1: F, f2: F) -> AA {
    f1().either(f2)
}

/// Return empty or a trivial value based on a predicate.
#[inline(always)]
#[must_use]
pub fn guard<A: Alternative<(), Applicative<()> = A>>(b: bool) -> A {
    if b {
        consume(())
    } else {
        empty()
    }
}