#[cfg(feature = "std")]
use std::boxed::Box;
#[cfg(all(not(feature = "std"), feature = "alloc"))]
use alloc::boxed::Box;
use karpal_core::functor::Functor;
use karpal_core::hkt::HKT;
use crate::fix::Fix;
use crate::schemes::ana;
#[allow(clippy::type_complexity)]
pub struct Nu<F: HKT, Seed> {
pub seed: Seed,
pub coalgebra: Box<dyn Fn(&Seed) -> F::Of<Seed>>,
}
impl<F: HKT, Seed> Nu<F, Seed> {
pub fn new(seed: Seed, coalgebra: impl Fn(&Seed) -> F::Of<Seed> + 'static) -> Self {
Nu {
seed,
coalgebra: Box::new(coalgebra),
}
}
pub fn observe(&self) -> F::Of<Seed> {
(self.coalgebra)(&self.seed)
}
pub fn to_fix(self) -> Fix<F>
where
F: Functor,
Seed: Clone,
{
let coalg = self.coalgebra;
ana(|s: Seed| coalg(&s), self.seed)
}
}
#[cfg(test)]
mod tests {
use super::*;
use karpal_core::hkt::OptionF;
#[test]
fn observe_once() {
let nu = Nu::<OptionF, u32>::new(3, |&s| if s == 0 { None } else { Some(s - 1) });
assert_eq!(nu.observe(), Some(2));
}
#[test]
fn observe_at_zero() {
let nu = Nu::<OptionF, u32>::new(0, |&s| if s == 0 { None } else { Some(s - 1) });
assert_eq!(nu.observe(), None);
}
#[test]
fn to_fix_converts() {
let nu = Nu::<OptionF, u32>::new(3, |&s| if s == 0 { None } else { Some(s - 1) });
let fixed = nu.to_fix();
fn count(f: Fix<OptionF>) -> u32 {
match f.unfix() {
None => 0,
Some(pred) => 1 + count(pred),
}
}
assert_eq!(count(fixed), 3);
}
}