// ==== main ==== // fn main() { let results = amb(&["the", "that", "a"]) >> move |a| amb(&["frog", "elephant", "thing"]) >> move |b| amb(&["walked", "treaded", "grows"]) >> move |c| amb(&["slowly", "quickly"]) >> move |d| assert(joins(a, b)) >> move |_| assert(joins(b, c)) >> move |_| assert(joins(c, d)) >> move |_| ret((a, b, c, d)); for (a, b, c, d) in results { println!("{} {} {} {}", a, b, c, d); } } fn joins(x: &str, y: &str) -> bool { x.chars().last() == y.chars().next() } // ==== Amb ==== // struct Amb(T); impl IntoIterator for Amb { type IntoIter = T; type Item = T::Item; fn into_iter(self) -> Self::IntoIter { self.0 } } impl std::ops::Shr for Amb where T: Iterator, U: Iterator, F: FnMut(T::Item) -> Amb, { type Output = Amb, F>>; fn shr(self, f: F) -> Self::Output { Self(self.0.flat_map(f)) } } fn amb(i: I) -> Amb { Amb(i.into_iter()) } fn assert(x: bool) -> Amb> { Amb(std::iter::once(()).filter(move |_| x)) } fn ret(x: T) -> Amb> { Amb(std::iter::once(x)) }