#[cfg(feature = "alloc")]
extern crate alloc;
#[cfg(feature = "alloc")]
use alloc::boxed::Box;
use crate::typeclasses::hkt::{CloneHKT, FunctorHKT, HKT};
#[cfg(feature = "alloc")]
#[derive(Debug, PartialEq, Eq)]
pub struct Cofree<F: FunctorHKT, A> {
pub attribute: A,
pub children: Box<F::Target<Cofree<F, A>>>,
}
#[cfg(feature = "alloc")]
impl<F: FunctorHKT + CloneHKT, A: Clone> Clone for Cofree<F, A> {
fn clone(&self) -> Self {
Cofree {
attribute: self.attribute.clone(),
children: Box::new(F::clone_hkt(&self.children)),
}
}
}
#[cfg(feature = "alloc")]
impl<F: FunctorHKT, A> Cofree<F, A> {
#[inline]
pub fn new(attribute: A, children: F::Target<Cofree<F, A>>) -> Self {
Cofree {
attribute,
children: Box::new(children),
}
}
#[inline]
pub fn extract(&self) -> &A {
&self.attribute
}
#[inline]
pub fn unwrap(self) -> F::Target<Cofree<F, A>> {
*self.children
}
#[inline]
pub fn children_ref(&self) -> &F::Target<Cofree<F, A>> {
&self.children
}
#[inline]
pub fn map_attr<B, G>(self, f: G) -> Cofree<F, B>
where
G: Fn(A) -> B + Clone,
F::Target<Cofree<F, A>>: Clone,
{
self.map_attr_impl(f)
}
#[inline]
fn map_attr_impl<B, G>(self, f: G) -> Cofree<F, B>
where
G: Fn(A) -> B + Clone,
F::Target<Cofree<F, A>>: Clone,
{
let new_attr = f(self.attribute);
let new_children = F::map(*self.children, |child| child.map_attr_impl(f.clone()));
Cofree {
attribute: new_attr,
children: Box::new(new_children),
}
}
}
#[cfg(feature = "alloc")]
pub struct CofreeWitness<F: FunctorHKT>(core::marker::PhantomData<F>);
#[cfg(feature = "alloc")]
impl<F: FunctorHKT> HKT for CofreeWitness<F> {
type Target<A> = Cofree<F, A>;
}
#[cfg(feature = "alloc")]
#[inline]
pub fn cofree_annotate<F, T, A, Ann>(value: T, annotate: Ann) -> Cofree<F, A>
where
F: FunctorHKT,
T: crate::recursion::traits::Recursiva<Base = F>,
Ann: Fn(&F::Target<Cofree<F, A>>) -> A + Clone,
{
cofree_annotate_impl(value, &annotate)
}
#[cfg(feature = "alloc")]
fn cofree_annotate_impl<F, T, A, Ann>(value: T, annotate: &Ann) -> Cofree<F, A>
where
F: FunctorHKT,
T: crate::recursion::traits::Recursiva<Base = F>,
Ann: Fn(&F::Target<Cofree<F, A>>) -> A,
{
let layer = value.project();
let children = F::map(layer, |child| cofree_annotate_impl(child, annotate));
let attr = annotate(&children);
Cofree::new(attr, children)
}
#[cfg(feature = "alloc")]
pub type CofreeNat<A> = Cofree<crate::recursion::base::NatFWitness, A>;
#[cfg(feature = "alloc")]
pub type CofreeList<E, A> = Cofree<crate::recursion::base::ListFWitness<E>, A>;
#[cfg(feature = "alloc")]
pub type CofreeExpr<A> = Cofree<crate::recursion::base::ExprFWitness, A>;