use alloc::boxed::Box;
use alloc::sync::Arc;
use core::marker::PhantomData;
use super::Effectus;
use crate::quantitative::{Multiplicitas, Omega, Usage};
pub use crate::quantitative::Semel;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub struct Affinis;
impl Usage for Affinis {
const VALUE: Multiplicitas = Multiplicitas::Semel; const ALLOWS_DISCARD: bool = true; const ALLOWS_DUP: bool = false; }
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub struct Nullus;
impl Usage for Nullus {
const VALUE: Multiplicitas = Multiplicitas::Nihil;
const ALLOWS_DISCARD: bool = false;
const ALLOWS_DUP: bool = false;
}
pub type Pluries = Omega;
pub struct Continuatio<A, B, M: Usage> {
inner: ContinuatioInner<A, B>,
_multiplicity: PhantomData<M>,
}
enum ContinuatioInner<A, B> {
Once(Box<dyn FnOnce(A) -> B + Send>),
Multi(Arc<dyn Fn(A) -> B + Send + Sync>),
}
impl<A: 'static, B: 'static> Continuatio<A, B, Semel> {
#[inline]
pub fn semel<F>(f: F) -> Self
where
F: FnOnce(A) -> B + Send + 'static,
{
Continuatio {
inner: ContinuatioInner::Once(Box::new(f)),
_multiplicity: PhantomData,
}
}
#[inline]
pub fn new<F>(f: F) -> Self
where
F: FnOnce(A) -> B + Send + 'static,
{
Self::semel(f)
}
#[inline]
pub fn resume(self, value: A) -> B {
match self.inner {
ContinuatioInner::Once(f) => f(value),
ContinuatioInner::Multi(f) => f(value),
}
}
}
impl<A: 'static, B: 'static> Continuatio<A, B, Affinis> {
#[inline]
pub fn affinis<F>(f: F) -> Self
where
F: FnOnce(A) -> B + Send + 'static,
{
Continuatio {
inner: ContinuatioInner::Once(Box::new(f)),
_multiplicity: PhantomData,
}
}
#[inline]
pub fn resume(self, value: A) -> B {
match self.inner {
ContinuatioInner::Once(f) => f(value),
ContinuatioInner::Multi(f) => f(value),
}
}
#[inline]
pub fn discard(self) {
}
}
impl<A: 'static, B: 'static> Continuatio<A, B, Pluries> {
#[inline]
pub fn pluries<F>(f: F) -> Self
where
F: Fn(A) -> B + Send + Sync + 'static,
{
Continuatio {
inner: ContinuatioInner::Multi(Arc::new(f)),
_multiplicity: PhantomData,
}
}
#[inline]
pub fn resume(&self, value: A) -> B {
match &self.inner {
ContinuatioInner::Multi(f) => f(value),
ContinuatioInner::Once(_) => {
panic!("Pluries continuation must use Multi inner")
}
}
}
#[inline]
pub fn resume_final(self, value: A) -> B {
match self.inner {
ContinuatioInner::Multi(f) => f(value),
ContinuatioInner::Once(f) => f(value),
}
}
}
impl<A, B> Clone for Continuatio<A, B, Pluries> {
#[inline]
fn clone(&self) -> Self {
match &self.inner {
ContinuatioInner::Multi(arc) => Continuatio {
inner: ContinuatioInner::Multi(Arc::clone(arc)),
_multiplicity: PhantomData,
},
ContinuatioInner::Once(_) => {
panic!("Cannot clone Once continuation as Pluries")
}
}
}
}
pub type ContinuatioSemel<A, B> = Continuatio<A, B, Semel>;
pub type ContinuatioAffinis<A, B> = Continuatio<A, B, Affinis>;
pub type ContinuatioPluries<A, B> = Continuatio<A, B, Pluries>;
impl<A: 'static, B: 'static> Continuatio<A, B, Semel> {
#[inline]
pub fn to_affinis(self) -> Continuatio<A, B, Affinis> {
Continuatio {
inner: self.inner,
_multiplicity: PhantomData,
}
}
}
impl<A: 'static, B: 'static, M: Usage> Continuatio<A, B, M> {
#[inline]
pub fn map<C: 'static, F>(self, f: F) -> Continuatio<A, C, M>
where
F: FnOnce(B) -> C + Clone + Send + Sync + 'static,
{
let mapped = match self.inner {
ContinuatioInner::Once(inner) => ContinuatioInner::Once(Box::new(move |a| f(inner(a)))),
ContinuatioInner::Multi(inner) => {
ContinuatioInner::Multi(Arc::new(move |a| f.clone()(inner(a))))
}
};
Continuatio {
inner: mapped,
_multiplicity: PhantomData,
}
}
#[inline]
pub fn contramap<C: 'static, F>(self, f: F) -> Continuatio<C, B, M>
where
F: FnOnce(C) -> A + Clone + Send + Sync + 'static,
{
let contramapped = match self.inner {
ContinuatioInner::Once(inner) => ContinuatioInner::Once(Box::new(move |c| inner(f(c)))),
ContinuatioInner::Multi(inner) => {
ContinuatioInner::Multi(Arc::new(move |c| inner(f.clone()(c))))
}
};
Continuatio {
inner: contramapped,
_multiplicity: PhantomData,
}
}
}
impl<A: 'static, B: 'static> Continuatio<A, B, Pluries> {
#[inline]
pub fn map_multi<C: 'static, F>(self, f: F) -> Continuatio<A, C, Pluries>
where
F: Fn(B) -> C + Send + Sync + 'static,
{
match self.inner {
ContinuatioInner::Multi(inner) => Continuatio {
inner: ContinuatioInner::Multi(Arc::new(move |a| f(inner(a)))),
_multiplicity: PhantomData,
},
ContinuatioInner::Once(_) => panic!("Expected Multi inner"),
}
}
#[inline]
pub fn contramap_multi<C: 'static, F>(self, f: F) -> Continuatio<C, B, Pluries>
where
F: Fn(C) -> A + Send + Sync + 'static,
{
match self.inner {
ContinuatioInner::Multi(inner) => Continuatio {
inner: ContinuatioInner::Multi(Arc::new(move |c| inner(f(c)))),
_multiplicity: PhantomData,
},
ContinuatioInner::Once(_) => panic!("Expected Multi inner"),
}
}
}
pub enum TractatorResultMulti<E: Effectus, A, B, M: Usage> {
Complete(A),
Suspended {
effect: E,
continuation: Continuatio<B, A, M>,
},
}
impl<E: Effectus, A, B, M: Usage> TractatorResultMulti<E, A, B, M> {
#[inline]
pub fn complete(value: A) -> Self {
TractatorResultMulti::Complete(value)
}
#[inline]
pub fn is_complete(&self) -> bool {
matches!(self, TractatorResultMulti::Complete(_))
}
#[inline]
pub fn is_suspended(&self) -> bool {
matches!(self, TractatorResultMulti::Suspended { .. })
}
}
impl<E: Effectus, A: 'static, B: 'static> TractatorResultMulti<E, A, B, Semel> {
#[inline]
pub fn suspended_semel<F>(effect: E, f: F) -> Self
where
F: FnOnce(B) -> A + Send + 'static,
{
TractatorResultMulti::Suspended {
effect,
continuation: Continuatio::semel(f),
}
}
}
impl<E: Effectus, A: 'static, B: 'static> TractatorResultMulti<E, A, B, Pluries> {
#[inline]
pub fn suspended_pluries<F>(effect: E, f: F) -> Self
where
F: Fn(B) -> A + Send + Sync + 'static,
{
TractatorResultMulti::Suspended {
effect,
continuation: Continuatio::pluries(f),
}
}
}
pub struct ChoicePoint<A, B> {
continuation: ContinuatioPluries<A, B>,
choices: alloc::vec::Vec<A>,
}
impl<A: Clone + 'static, B: 'static> ChoicePoint<A, B> {
#[inline]
pub fn new<F>(choices: alloc::vec::Vec<A>, f: F) -> Self
where
F: Fn(A) -> B + Send + Sync + 'static,
{
ChoicePoint {
continuation: Continuatio::pluries(f),
choices,
}
}
pub fn explore_all(self) -> alloc::vec::Vec<B> {
self.choices
.into_iter()
.map(|choice| self.continuation.resume(choice))
.collect()
}
pub fn find_first<F>(self, mut predicate: F) -> Option<B>
where
F: FnMut(&B) -> bool,
{
for choice in self.choices {
let result = self.continuation.resume(choice);
if predicate(&result) {
return Some(result);
}
}
None
}
}
pub trait TractatorContinuatio<E: Effectus> {
type Input;
type Output;
fn handle_with_continuation(
&self,
effect: E,
cont: ContinuatioSemel<Self::Input, Self::Output>,
) -> Self::Output;
}
pub enum TractatorResult<E: Effectus, A, B> {
Complete(A),
Suspended {
effect: E,
continuation: ContinuatioSemel<B, A>,
},
}
impl<E: Effectus, A, B> TractatorResult<E, A, B> {
#[inline]
pub fn complete(value: A) -> Self {
TractatorResult::Complete(value)
}
#[inline]
pub fn suspended(effect: E, continuation: ContinuatioSemel<B, A>) -> Self {
TractatorResult::Suspended {
effect,
continuation,
}
}
#[inline]
pub fn is_complete(&self) -> bool {
matches!(self, TractatorResult::Complete(_))
}
#[inline]
pub fn is_suspended(&self) -> bool {
matches!(self, TractatorResult::Suspended { .. })
}
pub fn map<C: 'static, F>(self, f: F) -> TractatorResult<E, C, B>
where
F: FnOnce(A) -> C + Clone + Send + Sync + 'static,
A: 'static,
B: 'static,
{
match self {
TractatorResult::Complete(a) => TractatorResult::Complete(f(a)),
TractatorResult::Suspended {
effect,
continuation,
} => TractatorResult::Suspended {
effect,
continuation: continuation.map(f),
},
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use alloc::vec;
#[test]
fn test_continuatio_semel() {
let cont: ContinuatioSemel<i32, i32> = Continuatio::semel(|x| x * 2);
let result = cont.resume(21);
assert_eq!(result, 42);
}
#[test]
fn test_continuatio_affinis() {
let cont: ContinuatioAffinis<i32, i32> = Continuatio::affinis(|x| x * 2);
let result = cont.resume(21);
assert_eq!(result, 42);
}
#[test]
fn test_continuatio_affinis_discard() {
let cont: ContinuatioAffinis<i32, i32> = Continuatio::affinis(|x| x * 2);
cont.discard(); }
#[test]
fn test_continuatio_pluries() {
let cont: ContinuatioPluries<i32, i32> = Continuatio::pluries(|x| x * 2);
let result1 = cont.resume(21);
let result2 = cont.resume(10);
assert_eq!(result1, 42);
assert_eq!(result2, 20);
}
#[test]
fn test_continuatio_pluries_clone() {
let cont1: ContinuatioPluries<i32, i32> = Continuatio::pluries(|x| x * 2);
let cont2 = cont1.clone();
let result1 = cont1.resume(21);
let result2 = cont2.resume(10);
assert_eq!(result1, 42);
assert_eq!(result2, 20);
}
#[test]
fn test_semel_to_affinis() {
let semel: ContinuatioSemel<i32, i32> = Continuatio::semel(|x| x * 2);
let affinis: ContinuatioAffinis<i32, i32> = semel.to_affinis();
let result = affinis.resume(21);
assert_eq!(result, 42);
}
#[test]
fn test_map() {
let cont: ContinuatioSemel<i32, i32> = Continuatio::semel(|x| x * 2);
let mapped = cont.map(|y| y + 1);
let result = mapped.resume(21);
assert_eq!(result, 43); }
#[test]
fn test_contramap() {
let cont: ContinuatioSemel<i32, i32> = Continuatio::semel(|x| x * 2);
let contramapped = cont.contramap(|s: &str| {
s.parse::<i32>()
.expect("test input should be a valid integer")
});
let result = contramapped.resume("21");
assert_eq!(result, 42);
}
#[test]
fn test_pluries_map_preserves_multi() {
let cont: ContinuatioPluries<i32, i32> = Continuatio::pluries(|x| x * 2);
let mapped = cont.map(|y| y + 1);
let result1 = mapped.resume(21);
let result2 = mapped.resume(10);
assert_eq!(result1, 43); assert_eq!(result2, 21);
let cloned = mapped.clone();
assert_eq!(cloned.resume(0), 1);
}
#[test]
fn test_pluries_contramap_preserves_multi() {
let cont: ContinuatioPluries<i32, i32> = Continuatio::pluries(|x| x * 2);
let pre = cont.contramap(|c: i32| c + 1);
assert_eq!(pre.resume(20), 42); assert_eq!(pre.resume(0), 2);
let cloned = pre.clone();
assert_eq!(cloned.resume(4), 10);
}
#[test]
fn test_pluries_map_multi() {
let cont: ContinuatioPluries<i32, i32> = Continuatio::pluries(|x| x * 2);
let mapped = cont.map_multi(|y| y + 1);
let result1 = mapped.resume(21);
let result2 = mapped.resume(10);
assert_eq!(result1, 43); assert_eq!(result2, 21); }
#[test]
fn test_choice_point_explore_all() {
let cp = ChoicePoint::new(vec![1, 2, 3], |x| x * 2);
let results = cp.explore_all();
assert_eq!(results, vec![2, 4, 6]);
}
#[test]
fn test_choice_point_find_first() {
let cp = ChoicePoint::new(vec![1, 2, 3, 4, 5], |x| x * 2);
let result = cp.find_first(|&x| x > 5);
assert_eq!(result, Some(6)); }
#[test]
fn test_tractator_result_multi_complete() {
struct TestEffect;
impl Effectus for TestEffect {}
let result: TractatorResultMulti<TestEffect, i32, i32, Semel> =
TractatorResultMulti::complete(42);
assert!(result.is_complete());
assert!(!result.is_suspended());
}
#[test]
fn test_tractator_result_multi_suspended() {
struct TestEffect;
impl Effectus for TestEffect {}
let result: TractatorResultMulti<TestEffect, i32, i32, Semel> =
TractatorResultMulti::suspended_semel(TestEffect, |x| x * 2);
assert!(result.is_suspended());
match result {
TractatorResultMulti::Suspended { continuation, .. } => {
assert_eq!(continuation.resume(21), 42);
}
_ => panic!("Expected Suspended"),
}
}
}