use super::functions::*;
pub struct VecFunctor<A>(pub Vec<A>);
pub struct Writer<A, W> {
value: A,
log: W,
}
impl<A, W: Default + Clone> Writer<A, W> {
pub fn new(value: A, log: W) -> Self {
Self { value, log }
}
pub fn pure(value: A) -> Self {
Self {
value,
log: W::default(),
}
}
pub fn get_value(self) -> A {
self.value
}
pub fn get_log(&self) -> &W {
&self.log
}
pub fn run(self) -> (A, W) {
(self.value, self.log)
}
}
#[allow(dead_code)]
pub struct DayConvolution<F, G, A> {
pub left: F,
pub right: G,
pub _phantom: std::marker::PhantomData<A>,
}
#[allow(dead_code)]
pub struct RepresentableFunctorExt<A> {
pub table: Vec<A>,
}
impl<A: Clone> RepresentableFunctorExt<A> {
pub fn tabulate(n: usize, f: impl Fn(usize) -> A) -> Self {
Self {
table: (0..n).map(f).collect(),
}
}
pub fn index(&self, i: usize) -> Option<&A> {
self.table.get(i)
}
}
pub struct ResultFunctor<A, E>(pub Result<A, E>);
pub struct Reader<E, A> {
run: Box<dyn Fn(E) -> A>,
}
impl<E: Clone + 'static, A: 'static> Reader<E, A> {
pub fn new(f: impl Fn(E) -> A + 'static) -> Self {
Self { run: Box::new(f) }
}
pub fn run_reader(self, env: E) -> A {
(self.run)(env)
}
pub fn map<B: 'static>(self, f: impl Fn(A) -> B + 'static) -> Reader<E, B> {
let run = self.run;
Reader::new(move |env: E| f(run(env)))
}
pub fn pure(a: A) -> Self
where
A: Clone,
{
Reader::new(move |_| a.clone())
}
}
#[allow(dead_code)]
pub struct ContravariantFunctor<A> {
pub predicate: Box<dyn Fn(A) -> bool>,
}
pub struct Pred<A>(pub Box<dyn Fn(A) -> bool>);
impl<A> Pred<A> {
pub fn new(f: impl Fn(A) -> bool + 'static) -> Self {
Pred(Box::new(f))
}
pub fn test(&self, a: A) -> bool {
(self.0)(a)
}
}
impl<A: 'static> Pred<A> {
pub fn contramap<B, F: Fn(B) -> A + 'static>(self, f: F) -> Pred<B> {
Pred(Box::new(move |b| (self.0)(f(b))))
}
}
#[allow(dead_code)]
pub struct ProfunctorCompose<A, B, C> {
pub left: Box<dyn Fn(A) -> B>,
pub right: Box<dyn Fn(B) -> C>,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Either<A, B> {
Left(A),
Right(B),
}
impl<A, B> Either<A, B> {
pub fn is_left(&self) -> bool {
matches!(self, Either::Left(_))
}
pub fn is_right(&self) -> bool {
matches!(self, Either::Right(_))
}
pub fn unwrap_left(self) -> A {
match self {
Either::Left(a) => a,
_ => panic!("Right"),
}
}
pub fn unwrap_right(self) -> B {
match self {
Either::Right(b) => b,
_ => panic!("Left"),
}
}
pub fn map_left<C, F: FnOnce(A) -> C>(self, f: F) -> Either<C, B> {
match self {
Either::Left(a) => Either::Left(f(a)),
Either::Right(b) => Either::Right(b),
}
}
pub fn map_right<D, G: FnOnce(B) -> D>(self, g: G) -> Either<A, D> {
match self {
Either::Left(a) => Either::Left(a),
Either::Right(b) => Either::Right(g(b)),
}
}
pub fn bimap<C, D, F: FnOnce(A) -> C, G: FnOnce(B) -> D>(self, f: F, g: G) -> Either<C, D> {
match self {
Either::Left(a) => Either::Left(f(a)),
Either::Right(b) => Either::Right(g(b)),
}
}
pub fn left(self) -> Option<A> {
match self {
Either::Left(a) => Some(a),
_ => None,
}
}
pub fn right(self) -> Option<B> {
match self {
Either::Right(b) => Some(b),
_ => None,
}
}
}
pub struct OptionFunctor<A>(pub Option<A>);
#[allow(dead_code)]
pub struct FunctorCompose<F, G, A> {
pub outer: F,
pub inner: G,
pub _phantom: std::marker::PhantomData<A>,
}