use crate::{
Applicative, Foldable, Functor, HKT, Monad, NoConstraint, Pure, Satisfies, Traversable,
};
pub struct OptionWitness;
impl HKT for OptionWitness {
type Constraint = NoConstraint;
type Type<T> = Option<T>;
}
impl Functor<OptionWitness> for OptionWitness {
fn fmap<A, B, Func>(
m_a: <OptionWitness as HKT>::Type<A>,
f: Func,
) -> <OptionWitness as HKT>::Type<B>
where
A: Satisfies<NoConstraint>,
B: Satisfies<NoConstraint>,
Func: FnMut(A) -> B,
{
m_a.map(f)
}
}
impl Pure<OptionWitness> for OptionWitness {
fn pure<T>(value: T) -> <OptionWitness as HKT>::Type<T>
where
T: Satisfies<NoConstraint>,
{
Some(value)
}
}
impl Applicative<OptionWitness> for OptionWitness {
fn apply<A, B, Func>(
f_ab: <OptionWitness as HKT>::Type<Func>,
f_a: <OptionWitness as HKT>::Type<A>,
) -> <OptionWitness as HKT>::Type<B>
where
A: Satisfies<NoConstraint> + Clone,
B: Satisfies<NoConstraint>,
Func: Satisfies<NoConstraint> + FnMut(A) -> B,
{
f_ab.and_then(|f| f_a.map(f))
}
}
impl Foldable<OptionWitness> for OptionWitness {
fn fold<A, B, Func>(fa: Option<A>, init: B, mut f: Func) -> B
where
Func: FnMut(B, A) -> B,
{
match fa {
Some(a) => f(init, a),
None => init,
}
}
}
impl Monad<OptionWitness> for OptionWitness {
fn bind<A, B, Func>(
m_a: <OptionWitness as HKT>::Type<A>,
mut f: Func,
) -> <OptionWitness as HKT>::Type<B>
where
A: Satisfies<NoConstraint>,
B: Satisfies<NoConstraint>,
Func: FnMut(A) -> <OptionWitness as HKT>::Type<B>,
{
match m_a {
Some(a) => f(a),
None => None,
}
}
}
impl Traversable<OptionWitness> for OptionWitness {
fn sequence<A, M>(
fa: <OptionWitness as HKT>::Type<M::Type<A>>,
) -> <M as HKT>::Type<<OptionWitness as HKT>::Type<A>>
where
M: Applicative<M> + HKT,
A: Clone + Satisfies<NoConstraint> + Satisfies<M::Constraint>,
M::Type<A>: Satisfies<NoConstraint>,
Option<A>: Satisfies<M::Constraint>,
{
match fa {
Some(m_a) => M::fmap(m_a, |a_val: A| Some(a_val)),
None => M::pure(None),
}
}
}