use alloc::vec;
use alloc::vec::Vec;
use crate::CausalTensor;
use crate::traits::tensor::Tensor;
use deep_causality_haft::{
Applicative, CoMonad, Collectable, DiagonalTraversable, Foldable, Functor, HKT, Monad, Pure,
Semigroupal, Traversable,
};
pub struct CausalTensorWitness;
impl HKT for CausalTensorWitness {
type Type<T> = CausalTensor<T>;
}
impl Functor<CausalTensorWitness> for CausalTensorWitness {
fn fmap<A, B, Func>(m_a: CausalTensor<A>, f: Func) -> CausalTensor<B>
where
Func: FnMut(A) -> B,
{
let shape = m_a.shape().to_vec();
let new_data: Vec<B> = m_a.into_vec().into_iter().map(f).collect();
CausalTensor::from_vec(new_data, &shape)
}
}
impl Foldable<CausalTensorWitness> for CausalTensorWitness {
fn fold<A, B, Func>(fa: CausalTensor<A>, init: B, f: Func) -> B
where
Func: FnMut(B, A) -> B,
{
fa.into_vec().into_iter().fold(init, f)
}
}
impl Collectable<CausalTensorWitness> for CausalTensorWitness {
fn collect<T, I>(items: I) -> CausalTensor<T>
where
I: IntoIterator<Item = T>,
{
let data: Vec<T> = items.into_iter().collect();
let len = data.len();
CausalTensor::from_vec(data, &[len])
}
}
impl Pure<CausalTensorWitness> for CausalTensorWitness {
fn pure<T>(value: T) -> CausalTensor<T> {
CausalTensor::from_vec(vec![value], &[])
}
}
impl Monad<CausalTensorWitness> for CausalTensorWitness {
fn bind<A, B, Func>(m_a: CausalTensor<A>, mut f: Func) -> CausalTensor<B>
where
Func: FnMut(A) -> <Self as HKT>::Type<B>,
{
let shape = m_a.shape().to_vec();
let count = m_a.len();
let mut result_data = Vec::with_capacity(count);
let mut every_step_gave_one = true;
let mut only_step_shape: Option<Vec<usize>> = None;
for a in m_a.into_vec() {
let mb = f(a);
if mb.len() != 1 {
every_step_gave_one = false;
}
if count == 1 {
only_step_shape = Some(mb.shape().to_vec());
}
result_data.extend(mb.into_vec());
}
let len = result_data.len();
if count == 1 && len != 1 {
let s = only_step_shape.expect("count is one, so the loop ran once");
return CausalTensor::from_vec(result_data, &s);
}
if every_step_gave_one {
CausalTensor::from_vec(result_data, &shape)
} else {
CausalTensor::from_vec(result_data, &[len])
}
}
}
impl Traversable<CausalTensorWitness> for CausalTensorWitness {
fn sequence<A, M>(fa: CausalTensor<M::Type<A>>) -> M::Type<CausalTensor<A>>
where
M: Applicative<M> + HKT,
A: Clone,
{
let shape = fa.shape().to_vec();
let mut acc: M::Type<Vec<A>> = M::pure(Vec::new());
for m_a in fa.into_vec() {
acc = M::apply(
M::fmap(acc, |v: Vec<A>| {
move |a: A| {
let mut v = v.clone();
v.push(a);
v
}
}),
m_a,
);
}
M::fmap(acc, move |v| CausalTensor::from_vec(v, &shape))
}
}
impl CoMonad<CausalTensorWitness> for CausalTensorWitness {
fn extract<A>(fa: &CausalTensor<A>) -> A
where
A: Clone,
{
fa.as_slice()
.first()
.cloned()
.expect("CoMonad::extract cannot be called on an empty CausalTensor.")
}
fn extend<A, B, Func>(fa: &CausalTensor<A>, mut f: Func) -> CausalTensor<B>
where
Func: FnMut(&CausalTensor<A>) -> B,
A: Clone,
{
let len = fa.len();
let shape = fa.shape().to_vec();
let new_data: Vec<B> = (0..len)
.map(|i| {
let view = fa.shifted_view(i);
f(&view)
})
.collect();
CausalTensor::from_vec(new_data, &shape)
}
}
impl Applicative<CausalTensorWitness> for CausalTensorWitness {
fn apply<A, B, Func>(f_ab: CausalTensor<Func>, f_a: CausalTensor<A>) -> CausalTensor<B>
where
A: Clone,
Func: FnMut(A) -> B,
{
let shape = f_a.shape().to_vec();
let funcs = f_ab.into_vec();
let args = f_a.into_vec();
let n_funcs = funcs.len();
let mut data: Vec<B> = Vec::with_capacity(n_funcs.saturating_mul(args.len()));
for mut f in funcs {
for a in args.iter() {
data.push(f(a.clone()));
}
}
if n_funcs == 1 {
CausalTensor::from_vec(data, &shape)
} else {
let len = data.len();
CausalTensor::from_vec(data, &[len])
}
}
}
impl DiagonalTraversable<CausalTensorWitness> for CausalTensorWitness {
fn sequence_zip<A, M>(
fa: CausalTensor<M::Type<A>>,
seed: M::Type<CausalTensor<A>>,
) -> M::Type<CausalTensor<A>>
where
M: Semigroupal<M> + HKT,
{
let shape = fa.shape().to_vec();
let cells = fa.into_vec();
if cells.is_empty() {
return seed;
}
let mut acc = seed;
for cell in cells {
acc = M::zip_with(acc, cell, |field, a| {
let mut values = field.into_vec();
values.push(a);
let len = values.len();
CausalTensor::from_vec(values, &[len])
});
}
M::fmap(acc, move |field| {
CausalTensor::from_vec(field.into_vec(), &shape)
})
}
}