use core::marker::PhantomData;
use crate::apply::Apply;
use crate::combinator::id;
use crate::constant1;
use crate::functor::Functor;
use crate::higher::Higher;
pub trait FlatMap<B>: Apply<B> {
fn flat_map<F>(self, f: F) -> Self::Target<B>
where
F: FnMut(Self::Param) -> Self::Target<B>;
#[inline]
fn flatten(self) -> Self::Target<B>
where
Self: FlatMap<B, Param = <Self as Higher>::Target<B>> + Sized,
{
self.flat_map(id)
}
fn m_product<F>(self, mut f: F) -> Self::Target<(Self::Param, B)>
where
F: FnMut(Self::Param) -> Self::Target<B>,
Self: FlatMap<(<Self as Higher>::Param, B)> + Sized,
Self::Param: Copy,
Self::Target<B>:
Functor<(Self::Param, B), Target<(Self::Param, B)> = Self::Target<(Self::Param, B)>>,
{
self.flat_map(|a| f(a).map(|b| (a, b)))
}
#[inline]
fn if_m<T, F>(self, mut if_true: T, mut if_false: F) -> Self::Target<B>
where
T: FnMut() -> Self::Target<B>,
F: FnMut() -> Self::Target<B>,
Self: FlatMap<B, Param = bool> + Sized,
{
self.flat_map(|x| if x { if_true() } else { if_false() })
}
fn flat_tap<F>(self, mut f: F) -> Self
where
F: FnMut(Self::Param) -> Self::Target<B>,
Self: FlatMap<<Self as Higher>::Param, Target<<Self as Higher>::Param> = Self> + Sized,
Self::Param: Copy,
Self::Target<B>: Functor<Self::Param, Target<Self::Param> = Self>,
{
#[inline]
fn internal<FA: FlatMap<<FA as Higher>::Param, Target<<FA as Higher>::Param> = FA>>(
fa: FA,
g: impl FnMut(FA::Param) -> FA,
) -> FA {
fa.flat_map(g)
}
internal(self, |a| f(a).map(constant1!(a)))
}
}
#[macro_export]
macro_rules! flatmap_iter {
($name:ident) => {
impl<A, B> $crate::flatmap::FlatMap<B> for $name<A>
{
#[inline]
fn flat_map<F>(self, f: F) -> Self::Target<B>
where
F: FnMut(A) -> Self::Target<B>,
{
self.into_iter().flat_map(f).collect::<$name<B>>()
}
}
};
($name:ident, $ct:tt $(+ $dt:tt )*) => {
impl<A: $ct $(+ $dt )*, B: $ct $(+ $dt )*> $crate::flatmap::FlatMap<B> for $name<A> {
#[inline]
fn flat_map<F>(self, f: F) -> Self::Target<B>
where
F: FnMut(A) -> Self::Target<B>,
{
self.into_iter().flat_map(f).collect::<$name<B>>()
}
}
};
}
impl<A, B> FlatMap<B> for PhantomData<A> {
#[inline]
fn flat_map<F>(self, _f: F) -> PhantomData<B>
where
F: FnMut(A) -> PhantomData<B>,
{
PhantomData
}
}
impl<A, B> FlatMap<B> for Option<A> {
#[inline]
fn flat_map<F>(self, f: F) -> Option<B>
where
F: FnMut(A) -> Option<B>,
{
self.and_then(f)
}
}
impl<A, B, E> FlatMap<B> for Result<A, E> {
#[inline]
fn flat_map<F>(self, f: F) -> Result<B, E>
where
F: FnMut(A) -> Result<B, E>,
{
self.and_then(f)
}
}
if_std! {
use std::boxed::Box;
use std::collections::*;
use std::hash::Hash;
use std::vec::Vec;
impl<A, B> FlatMap<B> for Box<A> {
#[inline]
fn flat_map<F>(self, mut f: F) -> Box<B>
where
F: FnMut(A) -> Box<B>,
{
f(*self)
}
}
flatmap_iter!(Vec);
flatmap_iter!(LinkedList);
flatmap_iter!(VecDeque);
flatmap_iter!(BinaryHeap, Ord);
flatmap_iter!(BTreeSet, Ord);
flatmap_iter!(HashSet, Eq + Hash);
impl<A, B, K: Eq + Hash> FlatMap<B> for HashMap<K, A> {
#[inline]
fn flat_map<F>(self, mut f: F) -> HashMap<K, B>
where
F: FnMut(A) -> HashMap<K, B>,
{
self.into_iter().flat_map(|(_, v)| f(v)).collect()
}
}
}