use crate::traits::monad::Monad;
use std::marker::PhantomData;
use std::sync::Arc;
pub type ContTFn<M, A> = dyn Fn(Arc<dyn Fn(A) -> M + Send + Sync>) -> M + Send + Sync;
#[derive(Clone)]
pub struct ContT<R, M, A> {
pub run_cont: Arc<ContTFn<M, A>>,
_phantom: PhantomData<(R, A)>,
}
impl<R, M, A> ContT<R, M, A> {
pub fn new<F>(f: F) -> Self
where
F: Fn(Arc<dyn Fn(A) -> M + Send + Sync>) -> M + Send + Sync + 'static,
{
ContT {
run_cont: Arc::new(f),
_phantom: PhantomData,
}
}
pub fn run<FN>(&self, k: FN) -> M
where
FN: Fn(A) -> M + Send + Sync + 'static,
{
(self.run_cont)(Arc::new(k))
}
pub fn pure(a: A) -> Self
where
M: Clone + 'static,
A: Clone + Send + Sync + 'static,
R: 'static,
{
ContT::new(move |k| k(a.clone()))
}
}
impl<R, M, A> ContT<R, M, A> {
pub fn bind<B, F>(self, f: F) -> ContT<R, M, B>
where
F: Fn(A) -> ContT<R, M, B> + Send + Sync + 'static,
A: Send + Sync + 'static,
B: Send + Sync + 'static,
M: 'static,
{
let f = Arc::new(f);
ContT::new(move |k| {
let run_cont = self.run_cont.clone();
let f = f.clone();
run_cont(Arc::new(move |a| {
let fb = f.clone()(a);
(fb.run_cont)(k.clone())
}))
})
}
pub fn fmap<B, F>(self, f: F) -> ContT<R, M, B>
where
F: Fn(A) -> B + Send + Sync + 'static,
A: Send + Sync + 'static,
B: Send + Sync + 'static,
M: 'static,
{
let f = Arc::new(f);
ContT::new(move |k| {
let run_cont = self.run_cont.clone();
let f = f.clone();
run_cont(Arc::new(move |a| k(f.clone()(a))))
})
}
pub fn apply<B>(self, cf: ContT<R, M, Arc<dyn Fn(A) -> B + Send + Sync>>) -> ContT<R, M, B>
where
A: Send + Sync + 'static,
B: Send + Sync + 'static,
M: 'static,
{
ContT::new(move |k| {
let run_val = self.run_cont.clone();
let run_func = cf.run_cont.clone();
let k = Arc::new(k);
run_func(Arc::new(move |f| {
let run_val = run_val.clone();
let k = k.clone();
run_val(Arc::new(move |a| k.clone()(f(a))))
}))
})
}
pub fn call_cc<B, F>(f: F) -> ContT<R, M, A>
where
F: Fn(Arc<dyn Fn(A) -> ContT<R, M, B> + Send + Sync>) -> ContT<R, M, A>
+ Send
+ Sync
+ 'static,
A: Clone + Send + Sync + 'static,
B: Send + Sync + 'static,
M: 'static,
{
let f = Arc::new(f);
ContT::new(move |k| {
let k_clone = k.clone();
let escape = Arc::new(move |a: A| {
let k_inner = k_clone.clone();
ContT::new(move |_ignored| k_inner(a.clone()))
});
f.clone()(escape).run_cont.clone()(k)
})
}
}
use crate::transformers::MonadTransformer;
impl<R, M: Monad + Clone + Send + Sync + 'static, A: Send + Sync + 'static> MonadTransformer
for ContT<R, M, A>
{
type BaseMonad = M;
fn lift(base: Self::BaseMonad) -> Self {
ContT::new(move |_k| base.clone())
}
}
impl<R, A> ContT<R, crate::datatypes::id::Id<R>, A> {
pub fn to_cont(self) -> crate::datatypes::cont::Cont<R, A> {
crate::datatypes::cont::Cont { inner: self }
}
pub fn from_cont(cont: crate::datatypes::cont::Cont<R, A>) -> Self {
cont.inner
}
}