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 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225
#![deny(unsafe_code, nonstandard_style)]
#![forbid(rust_2018_idioms)]
#![warn(unreachable_pub, missing_debug_implementations)]
#![allow(rustdoc::bare_urls)]
#![doc = include_str!("../README.md")]
#![cfg_attr(not(feature = "std"), no_std)]
pub use higher_derive::{Bifunctor, Functor};
pub mod semigroup;
#[doc(inline)]
pub use crate::semigroup::Semigroup;
pub mod monoid;
#[doc(inline)]
pub use crate::monoid::Monoid;
pub mod functor;
#[doc(inline)]
pub use crate::functor::Functor;
pub mod contra;
#[doc(inline)]
pub use crate::contra::Contravariant;
pub mod bifunctor;
#[doc(inline)]
pub use crate::bifunctor::Bifunctor;
pub mod profunctor;
#[doc(inline)]
pub use crate::profunctor::Profunctor;
pub mod pure;
#[doc(inline)]
pub use crate::pure::Pure;
pub mod apply;
#[doc(inline)]
pub use crate::apply::Apply;
pub mod bind;
#[doc(inline)]
pub use crate::bind::Bind;
pub mod applicative;
#[doc(inline)]
pub use crate::applicative::Applicative;
pub mod monad;
#[doc(inline)]
pub use crate::monad::Monad;
pub mod foldable;
#[doc(inline)]
pub use crate::foldable::Foldable;
pub mod algebras;
pub mod effect;
pub mod rings;
#[cfg(feature = "io")]
pub mod io;
/// Monadic do notation.
///
/// This macro provides some syntactic sugar to make monads easier to read and
/// write.
///
/// It takes a series of expressions evaluating to monads, separated by
/// semicolons, and chains them together using [`bind`](Bind::bind).
///
/// The last expression may be preceded by the `yield` keyword, which will
/// automatically wrap the result up into a monad using [`pure`](Pure::pure).
/// Otherwise it must be a plain expression returning a monad.
///
/// Expressions before the last may be binding expressions, binding the result
/// of the monadic computation to a named variable available to the subsequent
/// expressions. If they don't have a binding, the result of the computation is
/// discarded. A binding expression looks like this:
///
/// ```text
/// variable <= expression;
/// ```
///
/// # Examples
///
/// The simplest example of monadic do notation is using the [`Option`](Option)
/// type. It will run through the list of expressions as long as they keep
/// evaluating to [`Some`](Option::Some), but if an expression should return
/// [`None`](Option::None), it will discard the subsequent computations and
/// immediately return [`None`](Option::None).
///
/// We'll illustrate with integer division using
/// [`usize::checked_div`](usize::checked_div), which returns an
/// `Option<usize>`:
///
/// ```
/// # use higher::run;
/// # assert_eq!(
/// run! {
/// x <= 16usize.checked_div(2);
/// // x = 16 / 2 = 8
/// y <= x.checked_div(2);
/// // y = x / 2 = 8 / 2 = 4
/// z <= y.checked_div(2);
/// // z = y / 2 = 4 / 2 = 2
/// yield x + y + z
/// // returns Some(x + y + z) = Some(8 + 4 + 2) = Some(14)
/// }
/// # , Some(14));
/// ```
///
/// And for a failing example, when we divide by zero:
///
/// ```
/// # use higher::run;
/// # assert_eq!(
/// run! {
/// x <= 16usize.checked_div(2);
/// // x = 16 / 2 = 8
/// y <= x.checked_div(0);
/// // Division by zero returns None, the remaining expressions are ignored
/// z <= y.checked_div(2);
/// yield x + y + z
/// // returns None
/// }
/// # , None);
/// ```
#[macro_export]
macro_rules! run {
(yield $result:expr) => {
$crate::Pure::pure($result)
};
($result:expr) => {
$result
};
($binding:ident <= $comp:expr; $($tail:tt)*) => {
$crate::Bind::bind($comp, move |$binding| run!($($tail)*))
};
($comp:expr; $($tail:tt)*) => {
$crate::Bind::bind($comp, move |_| run!($($tail)*))
}
}
#[cfg(test)]
mod test {
#[test]
fn do_notation() {
// The standard list monad test.
assert_eq!(
run! {
x <= vec![1, 2];
y <= vec![x, x + 1];
yield (x, y)
},
vec![(1, 1), (1, 2), (2, 2), (2, 3)]
);
// Option with yield.
assert_eq!(
run! {
x <= 25u32.checked_div(2);
y <= x.checked_div(3);
z <= 9u32.checked_div(y);
yield x + y + z
},
Some(18)
);
// Option which fails.
assert_eq!(
run! {
x <= 5u32.checked_div(2);
y <= x.checked_div(8);
z <= 9u32.checked_div(y);
yield x + y + z
},
None
);
// Option with manual wrap.
assert_eq!(
run! {
x <= 25u32.checked_div(2);
y <= x.checked_div(3);
z <= 9u32.checked_div(y);
Some(x + y + z)
},
Some(18)
);
// Option without binding.
assert_eq!(
run! {
2u32.checked_div(2);
2u32.checked_div(1)
},
Some(2)
);
// Option without binding which fails.
assert_eq!(
run! {
2u32.checked_div(0);
2u32.checked_div(1)
},
None
);
// Options with different types.
assert_eq!(
run! {
s <= Some("64");
x <= s.parse::<u32>().ok();
y <= x.checked_div(2);
yield y
},
Some(32)
);
}
}