use super::continuation_v2::ContinuatioSemel;
use core::marker::PhantomData;
pub trait EffectusAlgebraicus: Send + Sync + 'static {
type Result: Send + 'static;
}
#[derive(Debug)]
pub struct Operatio<E: EffectusAlgebraicus> {
effect: E,
}
impl<E: EffectusAlgebraicus> Operatio<E> {
#[inline]
pub fn new(effect: E) -> Self {
Operatio { effect }
}
#[inline]
pub fn effect(&self) -> &E {
&self.effect
}
#[inline]
pub fn into_effect(self) -> E {
self.effect
}
}
pub enum ComputatioStatus<E: EffectusAlgebraicus, A> {
Completus(A),
Suspensus {
operatio: E,
continuatio: ContinuatioSemel<E::Result, ComputatioStatus<E, A>>,
},
}
impl<E: EffectusAlgebraicus, A> ComputatioStatus<E, A> {
#[inline]
pub fn complete(value: A) -> Self {
ComputatioStatus::Completus(value)
}
#[inline]
pub fn is_complete(&self) -> bool {
matches!(self, ComputatioStatus::Completus(_))
}
#[inline]
pub fn is_suspended(&self) -> bool {
matches!(self, ComputatioStatus::Suspensus { .. })
}
#[inline]
pub fn unwrap(self) -> A {
match self {
ComputatioStatus::Completus(a) => a,
ComputatioStatus::Suspensus { .. } => panic!("Computation is suspended"),
}
}
#[inline]
pub fn expect(self, msg: &str) -> A {
match self {
ComputatioStatus::Completus(a) => a,
ComputatioStatus::Suspensus { .. } => panic!("{}", msg),
}
}
}
pub trait TractatorAlgebraicus<E: EffectusAlgebraicus>: Sized {
type Output;
fn handle_return(&self, value: Self::Output) -> Self::Output;
fn handle_operation(
&mut self,
operation: E,
continuation: ContinuatioSemel<E::Result, Self::Output>,
) -> Self::Output;
}
pub fn run_with_handler<E, H, A, F>(handler: &mut H, computation: F) -> A
where
E: EffectusAlgebraicus,
H: TractatorAlgebraicus<E, Output = A>,
F: FnOnce() -> ComputatioStatus<E, A>,
A: 'static,
{
match computation() {
ComputatioStatus::Completus(a) => handler.handle_return(a),
ComputatioStatus::Suspensus {
operatio,
continuatio,
} => {
let wrapped_cont = continuatio.map(|status: ComputatioStatus<E, A>| {
match status {
ComputatioStatus::Completus(a) => a,
ComputatioStatus::Suspensus { .. } => {
panic!("Nested effects require deep handlers")
}
}
});
handler.handle_operation(operatio, wrapped_cont)
}
}
}
pub fn pure_effect<E: EffectusAlgebraicus, A>(value: A) -> ComputatioStatus<E, A> {
ComputatioStatus::Completus(value)
}
#[derive(Debug, Clone, Copy, Default)]
pub struct IdentityHandler;
impl<E: EffectusAlgebraicus<Result = A>, A: Clone + 'static> TractatorAlgebraicus<E>
for IdentityHandler
{
type Output = A;
#[inline]
fn handle_return(&self, value: A) -> A {
value
}
fn handle_operation(&mut self, _operation: E, _continuation: ContinuatioSemel<A, A>) -> A {
panic!("IdentityHandler cannot handle effects")
}
}
pub trait HandledBy<H>: EffectusAlgebraicus + Sized
where
H: TractatorAlgebraicus<Self>,
{
}
impl<E, H> HandledBy<H> for E
where
E: EffectusAlgebraicus + Sized,
H: TractatorAlgebraicus<E>,
{
}
pub struct ClosureHandler<E, A, RetFn, OpFn>
where
E: EffectusAlgebraicus,
RetFn: Fn(A) -> A,
OpFn: FnMut(E, ContinuatioSemel<E::Result, A>) -> A,
{
return_fn: RetFn,
operation_fn: OpFn,
_phantom: PhantomData<(E, A)>,
}
impl<E, A, RetFn, OpFn> ClosureHandler<E, A, RetFn, OpFn>
where
E: EffectusAlgebraicus,
RetFn: Fn(A) -> A,
OpFn: FnMut(E, ContinuatioSemel<E::Result, A>) -> A,
{
pub fn new(return_fn: RetFn, operation_fn: OpFn) -> Self {
ClosureHandler {
return_fn,
operation_fn,
_phantom: PhantomData,
}
}
}
impl<E, A, RetFn, OpFn> TractatorAlgebraicus<E> for ClosureHandler<E, A, RetFn, OpFn>
where
E: EffectusAlgebraicus,
A: 'static,
RetFn: Fn(A) -> A,
OpFn: FnMut(E, ContinuatioSemel<E::Result, A>) -> A,
{
type Output = A;
#[inline]
fn handle_return(&self, value: A) -> A {
(self.return_fn)(value)
}
#[inline]
fn handle_operation(
&mut self,
operation: E,
continuation: ContinuatioSemel<E::Result, A>,
) -> A {
(self.operation_fn)(operation, continuation)
}
}
pub fn make_handler<E, A, RetFn, OpFn>(
return_fn: RetFn,
operation_fn: OpFn,
) -> ClosureHandler<E, A, RetFn, OpFn>
where
E: EffectusAlgebraicus,
RetFn: Fn(A) -> A,
OpFn: FnMut(E, ContinuatioSemel<E::Result, A>) -> A,
{
ClosureHandler::new(return_fn, operation_fn)
}
pub struct DefaultHandler<E: EffectusAlgebraicus, A> {
_effect: PhantomData<E>,
_output: PhantomData<A>,
}
impl<E: EffectusAlgebraicus, A> DefaultHandler<E, A>
where
E::Result: Default,
{
pub fn new() -> Self {
DefaultHandler {
_effect: PhantomData,
_output: PhantomData,
}
}
}
impl<E: EffectusAlgebraicus, A> Default for DefaultHandler<E, A>
where
E::Result: Default,
{
fn default() -> Self {
Self::new()
}
}
impl<E: EffectusAlgebraicus, A: 'static> TractatorAlgebraicus<E> for DefaultHandler<E, A>
where
E::Result: Default,
{
type Output = A;
#[inline]
fn handle_return(&self, value: A) -> A {
value
}
#[inline]
fn handle_operation(
&mut self,
_operation: E,
continuation: ContinuatioSemel<E::Result, A>,
) -> A {
continuation.resume(E::Result::default())
}
}
pub fn default_handler<E, A>() -> DefaultHandler<E, A>
where
E: EffectusAlgebraicus,
A: 'static,
E::Result: Default,
{
DefaultHandler::new()
}
pub struct HandlerConfig<E: EffectusAlgebraicus> {
_effect: PhantomData<E>,
}
impl<E: EffectusAlgebraicus> Default for HandlerConfig<E> {
fn default() -> Self {
Self::new()
}
}
impl<E: EffectusAlgebraicus> HandlerConfig<E> {
pub fn new() -> Self {
HandlerConfig {
_effect: PhantomData,
}
}
pub fn with_closures<A, RetFn, OpFn>(
self,
return_fn: RetFn,
operation_fn: OpFn,
) -> ClosureHandler<E, A, RetFn, OpFn>
where
RetFn: Fn(A) -> A,
OpFn: FnMut(E, ContinuatioSemel<E::Result, A>) -> A,
{
ClosureHandler::new(return_fn, operation_fn)
}
pub fn identity(self) -> IdentityHandler {
IdentityHandler
}
}
#[cfg(test)]
mod tests {
use super::*;
#[derive(Debug, Clone)]
enum TestOp {
GetValue,
SetValue(i32),
}
impl EffectusAlgebraicus for TestOp {
type Result = i32;
}
struct TestHandler {
state: i32,
}
impl TestHandler {
fn new(initial: i32) -> Self {
TestHandler { state: initial }
}
}
impl TractatorAlgebraicus<TestOp> for TestHandler {
type Output = i32;
fn handle_return(&self, value: i32) -> i32 {
value
}
fn handle_operation(&mut self, op: TestOp, cont: ContinuatioSemel<i32, i32>) -> i32 {
match op {
TestOp::GetValue => cont.resume(self.state),
TestOp::SetValue(v) => {
self.state = v;
cont.resume(v)
}
}
}
}
#[test]
fn test_pure_effect() {
let status: ComputatioStatus<TestOp, i32> = pure_effect(42);
assert!(status.is_complete());
assert_eq!(
status.expect(
"pure_effect should produce a complete ComputatioStatus with the wrapped value"
),
42
);
}
#[test]
fn test_computation_status() {
let complete: ComputatioStatus<TestOp, i32> = ComputatioStatus::complete(42);
assert!(complete.is_complete());
assert!(!complete.is_suspended());
}
#[test]
fn test_handler_return() {
let mut handler = TestHandler::new(0);
let result = run_with_handler(&mut handler, || pure_effect(42));
assert_eq!(result, 42);
}
#[test]
fn test_handler_operation() {
let mut handler = TestHandler::new(10);
let result = run_with_handler(&mut handler, || ComputatioStatus::Suspensus {
operatio: TestOp::GetValue,
continuatio: ContinuatioSemel::new(|x| ComputatioStatus::Completus(x * 2)),
});
assert_eq!(result, 20); }
#[test]
fn test_handler_set_operation() {
let mut handler = TestHandler::new(0);
let result = run_with_handler(&mut handler, || ComputatioStatus::Suspensus {
operatio: TestOp::SetValue(42),
continuatio: ContinuatioSemel::new(ComputatioStatus::Completus),
});
assert_eq!(result, 42);
assert_eq!(handler.state, 42);
}
#[test]
fn test_operatio() {
let op = Operatio::new(TestOp::GetValue);
match op.effect() {
TestOp::GetValue => {}
_ => panic!("Wrong operation"),
}
}
#[test]
fn test_closure_handler() {
let mut handler = make_handler(
|x: i32| x,
|op: TestOp, cont: ContinuatioSemel<i32, i32>| match op {
TestOp::GetValue => cont.resume(100),
TestOp::SetValue(v) => cont.resume(v),
},
);
let result = run_with_handler(&mut handler, || ComputatioStatus::Suspensus {
operatio: TestOp::GetValue,
continuatio: ContinuatioSemel::new(ComputatioStatus::Completus),
});
assert_eq!(result, 100);
}
#[test]
fn test_identity_handler() {
let mut handler = IdentityHandler;
let result: i32 =
run_with_handler::<TestOp, _, _, _>(&mut handler, || pure_effect::<TestOp, _>(42));
assert_eq!(result, 42);
}
#[test]
fn test_handler_config() {
let config: HandlerConfig<TestOp> = HandlerConfig::new();
let _identity = config.identity();
let _config2: HandlerConfig<TestOp> = HandlerConfig::default();
}
#[test]
fn test_handler_config_with_closures() {
let config: HandlerConfig<TestOp> = HandlerConfig::new();
let mut handler = config.with_closures(
|x: i32| x,
|op: TestOp, cont: ContinuatioSemel<i32, i32>| match op {
TestOp::GetValue => cont.resume(50),
TestOp::SetValue(v) => cont.resume(v),
},
);
let result = run_with_handler(&mut handler, || ComputatioStatus::Suspensus {
operatio: TestOp::GetValue,
continuatio: ContinuatioSemel::new(ComputatioStatus::Completus),
});
assert_eq!(result, 50);
}
}