#[cfg(feature = "alloc")]
extern crate alloc;
#[cfg(feature = "alloc")]
use alloc::boxed::Box;
use crate::typeclasses::hkt::{FunctorHKT, HKT};
#[cfg(feature = "alloc")]
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Free<F: FunctorHKT, A> {
Purus(A),
Suspensus(Box<F::Target<Free<F, A>>>),
}
#[cfg(feature = "alloc")]
impl<F: FunctorHKT, A> Free<F, A> {
#[inline]
pub fn purus(a: A) -> Self {
Free::Purus(a)
}
#[inline]
pub fn suspensus(layer: F::Target<Free<F, A>>) -> Self {
Free::Suspensus(Box::new(layer))
}
#[inline]
pub fn is_pure(&self) -> bool {
matches!(self, Free::Purus(_))
}
#[inline]
pub fn is_suspended(&self) -> bool {
matches!(self, Free::Suspensus(_))
}
#[inline]
pub fn map<B, G>(self, f: G) -> Free<F, B>
where
G: Fn(A) -> B + Clone,
{
self.map_impl(f)
}
fn map_impl<B, G>(self, f: G) -> Free<F, B>
where
G: Fn(A) -> B + Clone,
{
match self {
Free::Purus(a) => Free::Purus(f(a)),
Free::Suspensus(layer) => {
let mapped = F::map(*layer, |child| child.map_impl(f.clone()));
Free::Suspensus(Box::new(mapped))
}
}
}
#[inline]
pub fn flat_map<B, G>(self, f: G) -> Free<F, B>
where
G: Fn(A) -> Free<F, B> + Clone,
{
self.flat_map_impl(f)
}
fn flat_map_impl<B, G>(self, f: G) -> Free<F, B>
where
G: Fn(A) -> Free<F, B> + Clone,
{
match self {
Free::Purus(a) => f(a),
Free::Suspensus(layer) => {
let mapped = F::map(*layer, |child| child.flat_map_impl(f.clone()));
Free::Suspensus(Box::new(mapped))
}
}
}
#[inline]
pub fn lift_f(fa: F::Target<A>) -> Self
where
A: Clone,
{
Free::Suspensus(Box::new(F::map(fa, Free::purus)))
}
}
#[cfg(feature = "alloc")]
pub struct FreeWitness<F: FunctorHKT>(core::marker::PhantomData<F>);
#[cfg(feature = "alloc")]
impl<F: FunctorHKT> HKT for FreeWitness<F> {
type Target<A> = Free<F, A>;
}
#[cfg(feature = "alloc")]
#[inline]
pub fn iter_free<F, A, Step>(free: Free<F, A>, step: Step) -> A
where
F: FunctorHKT,
Step: Fn(F::Target<A>) -> A + Clone,
{
iter_free_impl(free, &step)
}
#[cfg(feature = "alloc")]
fn iter_free_impl<F, A, Step>(free: Free<F, A>, step: &Step) -> A
where
F: FunctorHKT,
Step: Fn(F::Target<A>) -> A,
{
match free {
Free::Purus(a) => a,
Free::Suspensus(layer) => {
let mapped = F::map(*layer, |child| iter_free_impl(child, step));
step(mapped)
}
}
}
#[cfg(feature = "alloc")]
pub type FreeNat<A> = Free<crate::recursion::base::NatFWitness, A>;
#[cfg(feature = "alloc")]
pub type FreeList<E, A> = Free<crate::recursion::base::ListFWitness<E>, A>;
#[cfg(feature = "alloc")]
pub type FreeExpr<A> = Free<crate::recursion::base::ExprFWitness, A>;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Aut<L, R> {
Sinister(L),
Dexter(R),
}
impl<L, R> Aut<L, R> {
#[inline]
pub fn sinister(l: L) -> Self {
Aut::Sinister(l)
}
#[inline]
pub fn dexter(r: R) -> Self {
Aut::Dexter(r)
}
#[inline]
pub fn is_sinister(&self) -> bool {
matches!(self, Aut::Sinister(_))
}
#[inline]
pub fn is_dexter(&self) -> bool {
matches!(self, Aut::Dexter(_))
}
#[inline]
pub fn map_sinister<B, F>(self, f: F) -> Aut<B, R>
where
F: FnOnce(L) -> B,
{
match self {
Aut::Sinister(l) => Aut::Sinister(f(l)),
Aut::Dexter(r) => Aut::Dexter(r),
}
}
#[inline]
pub fn map_dexter<B, F>(self, f: F) -> Aut<L, B>
where
F: FnOnce(R) -> B,
{
match self {
Aut::Sinister(l) => Aut::Sinister(l),
Aut::Dexter(r) => Aut::Dexter(f(r)),
}
}
#[inline]
pub fn bimap<A, B, F, G>(self, f: F, g: G) -> Aut<A, B>
where
F: FnOnce(L) -> A,
G: FnOnce(R) -> B,
{
match self {
Aut::Sinister(l) => Aut::Sinister(f(l)),
Aut::Dexter(r) => Aut::Dexter(g(r)),
}
}
}