use raskell::hdo;
#[derive(Debug, PartialEq)]
enum Inner {
Boom,
}
#[derive(Debug, PartialEq)]
enum Outer {
Wrapped,
Missing,
}
impl From<Inner> for Outer {
fn from(_: Inner) -> Self {
Outer::Wrapped
}
}
fn inner_ok() -> Result<i32, Inner> {
Ok(10)
}
fn inner_err() -> Result<i32, Inner> {
Err(Inner::Boom)
}
#[test]
fn try_bind_converts_error() {
let result: Result<i32, Outer> = hdo! {
x <-? inner_err();
pure x * 2
};
assert_eq!(result, Err(Outer::Wrapped));
}
#[test]
fn try_bind_passes_value_through() {
let result: Result<i32, Outer> = hdo! {
x <-? inner_ok();
pure x * 2
};
assert_eq!(result, Ok(20));
}
#[test]
fn try_bind_nested_in_plain_bind() {
let result: Result<i32, Outer> = hdo! {
a <- Ok(1);
b <-? inner_err();
pure a + b
};
assert_eq!(result, Err(Outer::Wrapped));
}
#[test]
fn try_bind_with_refutable_pattern() {
fn maybe() -> Result<Option<i32>, Inner> {
Ok(None)
}
let result: Result<i32, Outer> = hdo! {
Some(x) <-? maybe() throw Outer::Missing;
pure x
};
assert_eq!(result, Err(Outer::Missing));
}
#[test]
fn try_bind_with_ascription() {
let result: Result<i32, Outer> = hdo! {
Some(x): Option<i32> <-? Err(Inner::Boom) throw Outer::Missing;
pure x
};
assert_eq!(result, Err(Outer::Wrapped));
}
#[test]
fn list_bind_is_a_cartesian_product() {
let result: Vec<(i32, char)> = hdo! {
x <- vec![1, 2];
y <- vec!['a', 'b'];
pure (x, y)
};
assert_eq!(result, vec![(1, 'a'), (1, 'b'), (2, 'a'), (2, 'b')]);
}
#[test]
fn list_guard_filters() {
let result: Vec<i32> = hdo! {
x <- vec![1, 2, 3, 4];
guard x % 2 == 0;
pure x * 10
};
assert_eq!(result, vec![20, 40]);
}
#[test]
fn list_let_and_nested_guard() {
let result: Vec<i32> = hdo! {
x <- vec![1, 2, 3];
y <- vec![10, 20];
let sum = x + y;
guard sum > 12;
pure sum
};
assert_eq!(result, vec![21, 22, 13, 23]);
}
#[test]
fn empty_list_short_circuits() {
let result: Vec<i32> = hdo! {
x <- vec![1, 2];
y <- Vec::<i32>::new();
pure x + y
};
assert_eq!(result, Vec::<i32>::new());
}
#[test]
fn statement_expression_semantics_are_monadic() {
let mut values = vec![1];
let result = hdo! {
x <- Some(10);
values.pop();
pure x
};
assert_eq!(result, Some(10));
let mut empty: Vec<i32> = Vec::new();
let short_circuited = hdo! {
x <- Some(10);
empty.pop();
pure x
};
assert_eq!(short_circuited, None);
}
#[test]
fn discarding_an_action_keeps_it_out_of_the_chain() {
let mut empty: Vec<i32> = Vec::new();
let result = hdo! {
x <- Some(10);
let _ = empty.pop();
pure x
};
assert_eq!(result, Some(10));
}