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()
}
}