use crate::functor::{ExactlyOne, Functor};
use std::fmt::{Debug, Display};
pub trait FunctorWithContext: Functor {
type Context: Context;
fn fmap_with_context<A, B, F>(a: Self::Structure<A>, f: F) -> Self::Structure<B>
where
F: Fn(Self::Context, A) -> B;
}
impl<T> FunctorWithContext for ExactlyOne<T> {
type Context = NoContext;
fn fmap_with_context<A, B, F>(a: Self::Structure<A>, f: F) -> Self::Structure<B>
where
F: Fn(Self::Context, A) -> B,
{
Self::fmap(a, |a| f(NoContext, a))
}
}
impl<T> FunctorWithContext for Option<T> {
type Context = NoContext;
fn fmap_with_context<A, B, F>(a: Self::Structure<A>, f: F) -> Self::Structure<B>
where
F: Fn(Self::Context, A) -> B,
{
Self::fmap(a, |a| f(NoContext, a))
}
}
impl<T> FunctorWithContext for Vec<T> {
type Context = ListIndex;
fn fmap_with_context<A, B, F>(a: Self::Structure<A>, f: F) -> Self::Structure<B>
where
F: Fn(Self::Context, A) -> B,
{
Self::fmap(a.into_iter().enumerate().collect(), |(i, v)| {
f(ListIndex(i), v)
})
}
}
impl<T, const M: usize> FunctorWithContext for [T; M] {
type Context = ListIndex;
fn fmap_with_context<A, B, F>(a: Self::Structure<A>, f: F) -> Self::Structure<B>
where
F: Fn(Self::Context, A) -> B,
{
Self::fmap(
a.into_iter()
.enumerate()
.collect::<Vec<_>>()
.try_into()
.map_err(|_| "")
.unwrap(), |(i, v)| f(ListIndex(i), v),
)
}
}
pub trait Context: Debug + Display {}
#[derive(Debug)]
pub struct NoContext;
impl Context for NoContext {}
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd)]
pub struct ListIndex(pub usize);
impl Context for ListIndex {}