1use std::collections::HashMap;
6
7use super::functions::*;
8use std::fmt;
9
10pub struct AlgebraicEffect {
12 pub signature: Vec<(String, String, String)>,
14}
15impl AlgebraicEffect {
16 pub fn new(signature: Vec<(String, String, String)>) -> Self {
18 Self { signature }
19 }
20 pub fn effect_theory(&self) -> String {
22 format!(
23 "Algebraic theory with {} operations; models are algebras satisfying handler equations",
24 self.signature.len()
25 )
26 }
27 pub fn operations_are_equations(&self) -> bool {
29 true
30 }
31}
32#[allow(dead_code)]
37pub enum FreerComp {
38 Pure(String),
40 Impure {
42 effect: String,
44 op: String,
46 arg: String,
48 cont: Box<dyn FnOnce(String) -> FreerComp>,
50 },
51}
52#[allow(dead_code)]
53impl FreerComp {
54 pub fn pure(v: impl Into<String>) -> Self {
56 FreerComp::Pure(v.into())
57 }
58 pub fn impure(
60 effect: impl Into<String>,
61 op: impl Into<String>,
62 arg: impl Into<String>,
63 cont: impl FnOnce(String) -> FreerComp + 'static,
64 ) -> Self {
65 FreerComp::Impure {
66 effect: effect.into(),
67 op: op.into(),
68 arg: arg.into(),
69 cont: Box::new(cont),
70 }
71 }
72 pub fn interpret(self, handler: &dyn Fn(&str, &str, &str) -> String) -> String {
75 match self {
76 FreerComp::Pure(v) => v,
77 FreerComp::Impure {
78 effect,
79 op,
80 arg,
81 cont,
82 } => {
83 let result = handler(&effect, &op, &arg);
84 cont(result).interpret(handler)
85 }
86 }
87 }
88 pub fn is_pure(&self) -> bool {
90 matches!(self, FreerComp::Pure(_))
91 }
92}
93pub struct HandlerType {
95 pub input_type: String,
97 pub output_type: String,
99 pub effect_row: String,
101}
102impl HandlerType {
103 pub fn new(
105 input_type: impl Into<String>,
106 output_type: impl Into<String>,
107 effect_row: impl Into<String>,
108 ) -> Self {
109 Self {
110 input_type: input_type.into(),
111 output_type: output_type.into(),
112 effect_row: effect_row.into(),
113 }
114 }
115 pub fn handles_effect(&self, effect: &str) -> bool {
117 self.effect_row.contains(effect)
118 }
119 pub fn continuation_type(&self) -> String {
121 format!("{} -> Comp {{}} {}", self.input_type, self.output_type)
122 }
123}
124#[allow(dead_code)]
127pub struct EffectRowChecker {
128 pub declared_row: EffRow,
130 pub violations: Vec<String>,
132}
133#[allow(dead_code)]
134impl EffectRowChecker {
135 pub fn new(declared_row: EffRow) -> Self {
137 Self {
138 declared_row,
139 violations: vec![],
140 }
141 }
142 pub fn check_effect(&mut self, effect: &str) -> bool {
144 if self.declared_row.contains(effect) {
145 true
146 } else {
147 self.violations.push(effect.to_string());
148 false
149 }
150 }
151 pub fn check_all(&mut self, used_effects: &[&str]) -> bool {
153 let mut all_ok = true;
154 for eff in used_effects {
155 if !self.check_effect(eff) {
156 all_ok = false;
157 }
158 }
159 all_ok
160 }
161 pub fn has_violations(&self) -> bool {
163 !self.violations.is_empty()
164 }
165 pub fn violation_summary(&self) -> String {
167 if self.violations.is_empty() {
168 "No violations: all effects are within the declared row.".to_string()
169 } else {
170 format!(
171 "Violations: {:?} not in declared row {:?}",
172 self.violations,
173 self.declared_row.effect_names()
174 )
175 }
176 }
177 pub fn reset(&mut self) {
179 self.violations.clear();
180 }
181 pub fn is_sound_annotation(&self) -> bool {
183 !self.has_violations()
184 }
185}
186#[allow(dead_code)]
188pub struct LinearEffectTracker {
189 usage: HashMap<String, usize>,
191 linear_effects: Vec<String>,
193}
194#[allow(dead_code)]
195impl LinearEffectTracker {
196 pub fn new(linear_effects: Vec<String>) -> Self {
198 Self {
199 usage: HashMap::new(),
200 linear_effects,
201 }
202 }
203 pub fn use_effect(&mut self, effect: &str) {
205 *self.usage.entry(effect.to_string()).or_insert(0) += 1;
206 }
207 pub fn check_linear(&self, effect: &str) -> bool {
209 self.usage.get(effect).copied().unwrap_or(0) == 1
210 }
211 pub fn verify_all_linear(&self) -> bool {
213 self.linear_effects.iter().all(|e| self.check_linear(e))
214 }
215 pub fn usage_count(&self, effect: &str) -> usize {
217 self.usage.get(effect).copied().unwrap_or(0)
218 }
219 pub fn overused_effects(&self) -> Vec<String> {
221 self.linear_effects
222 .iter()
223 .filter(|e| self.usage.get(*e).copied().unwrap_or(0) > 1)
224 .cloned()
225 .collect()
226 }
227 pub fn unused_effects(&self) -> Vec<String> {
229 self.linear_effects
230 .iter()
231 .filter(|e| self.usage.get(*e).copied().unwrap_or(0) == 0)
232 .cloned()
233 .collect()
234 }
235 pub fn report(&self) -> String {
237 let overused = self.overused_effects();
238 let unused = self.unused_effects();
239 if overused.is_empty() && unused.is_empty() {
240 "Linear effects: all used exactly once (correct)".to_string()
241 } else {
242 format!(
243 "Linear effect violations: overused={:?}, unused={:?}",
244 overused, unused
245 )
246 }
247 }
248}
249pub enum Free<A> {
253 Pure(A),
255 Op {
257 effect: String,
259 op: String,
261 arg: String,
263 cont: Box<dyn FnOnce(String) -> Free<A>>,
265 },
266}
267impl<A> Free<A> {
268 pub fn pure(val: A) -> Self {
270 Free::Pure(val)
271 }
272 pub fn op(
274 effect: impl Into<String>,
275 op: impl Into<String>,
276 arg: impl Into<String>,
277 cont: impl FnOnce(String) -> Free<A> + 'static,
278 ) -> Self {
279 Free::Op {
280 effect: effect.into(),
281 op: op.into(),
282 arg: arg.into(),
283 cont: Box::new(cont),
284 }
285 }
286 pub fn fold<B: 'static>(
288 self,
289 ret: impl Fn(A) -> B + 'static,
290 alg: &'static dyn Fn(&str, &str, String, Box<dyn FnOnce(String) -> B>) -> B,
291 ) -> B
292 where
293 A: 'static,
294 {
295 match self {
296 Free::Pure(a) => ret(a),
297 Free::Op {
298 effect,
299 op,
300 arg,
301 cont,
302 } => {
303 let ret = std::sync::Arc::new(ret);
304 let ret2 = ret.clone();
305 let cont_b = Box::new(move |s: String| cont(s).fold_inner(ret2, alg));
306 alg(&effect, &op, arg, cont_b)
307 }
308 }
309 }
310 fn fold_inner<B: 'static>(
311 self,
312 ret: std::sync::Arc<impl Fn(A) -> B + 'static>,
313 alg: &'static dyn Fn(&str, &str, String, Box<dyn FnOnce(String) -> B>) -> B,
314 ) -> B
315 where
316 A: 'static,
317 {
318 match self {
319 Free::Pure(a) => ret(a),
320 Free::Op {
321 effect,
322 op,
323 arg,
324 cont,
325 } => {
326 let ret2 = ret.clone();
327 let cont_b = Box::new(move |s: String| cont(s).fold_inner(ret2, alg));
328 alg(&effect, &op, arg, cont_b)
329 }
330 }
331 }
332}
333pub struct EffectHandler {
335 pub effect: String,
337 pub handler_fn: String,
339}
340impl EffectHandler {
341 pub fn new(effect: impl Into<String>, handler_fn: impl Into<String>) -> Self {
343 Self {
344 effect: effect.into(),
345 handler_fn: handler_fn.into(),
346 }
347 }
348 pub fn deep_handler(&self) -> String {
350 format!(
351 "Deep handler for {}: handles all continuations recursively",
352 self.effect
353 )
354 }
355 pub fn shallow_handler(&self) -> String {
357 format!(
358 "Shallow handler for {}: one-shot, does not re-handle continuation",
359 self.effect
360 )
361 }
362 pub fn effect_elimination(&self) -> String {
364 format!(
365 "handle[{}]: Comp (E | R) A -> Comp R A via handler {}",
366 self.effect, self.handler_fn
367 )
368 }
369}
370#[derive(Debug, Clone, Default)]
372pub struct EffRow {
373 effects: Vec<String>,
375}
376impl EffRow {
377 pub fn empty() -> Self {
379 EffRow { effects: vec![] }
380 }
381 pub fn extend(&self, eff: impl Into<String>) -> Self {
383 let mut new = self.clone();
384 let name = eff.into();
385 if !new.effects.contains(&name) {
386 new.effects.push(name);
387 }
388 new
389 }
390 pub fn contains(&self, eff: &str) -> bool {
392 self.effects.iter().any(|e| e == eff)
393 }
394 pub fn lacks(&self, eff: &str) -> bool {
396 !self.contains(eff)
397 }
398 pub fn is_subset_of(&self, other: &EffRow) -> bool {
400 self.effects.iter().all(|e| other.contains(e))
401 }
402 pub fn union(&self, other: &EffRow) -> Self {
404 let mut new = self.clone();
405 for e in &other.effects {
406 if !new.effects.contains(e) {
407 new.effects.push(e.clone());
408 }
409 }
410 new
411 }
412 pub fn effect_names(&self) -> &[String] {
414 &self.effects
415 }
416 pub fn is_pure(&self) -> bool {
418 self.effects.is_empty()
419 }
420}
421#[derive(Debug, Clone)]
423pub struct EffSig {
424 pub name: String,
426 pub operations: Vec<OpDesc>,
428}
429impl EffSig {
430 pub fn new(name: impl Into<String>, ops: Vec<OpDesc>) -> Self {
432 EffSig {
433 name: name.into(),
434 operations: ops,
435 }
436 }
437 pub fn get_op(&self, op_name: &str) -> Option<&OpDesc> {
439 self.operations.iter().find(|op| op.name == op_name)
440 }
441}
442pub struct Continuation<A, B> {
444 func: Box<dyn FnOnce(A) -> B>,
445}
446impl<A, B> Continuation<A, B> {
447 pub fn new(f: impl FnOnce(A) -> B + 'static) -> Self {
449 Continuation { func: Box::new(f) }
450 }
451 pub fn resume(self, val: A) -> B {
453 (self.func)(val)
454 }
455}
456pub struct EffPoly<A> {
461 compute: Box<dyn Fn(&EffRow) -> A>,
463}
464impl<A> EffPoly<A> {
465 pub fn new(f: impl Fn(&EffRow) -> A + 'static) -> Self {
467 EffPoly {
468 compute: Box::new(f),
469 }
470 }
471 pub fn instantiate(&self, row: &EffRow) -> A {
473 (self.compute)(row)
474 }
475}
476pub struct DeepHandler<A, B> {
481 pub effect_name: String,
483 pub val_clause: Box<dyn Fn(A) -> B>,
485 pub op_clauses: HashMap<String, Box<dyn Fn(String, Box<dyn Fn(String) -> B>) -> B>>,
487}
488impl<A, B: 'static> DeepHandler<A, B> {
489 pub fn new(effect_name: impl Into<String>, val_clause: impl Fn(A) -> B + 'static) -> Self {
491 DeepHandler {
492 effect_name: effect_name.into(),
493 val_clause: Box::new(val_clause),
494 op_clauses: HashMap::new(),
495 }
496 }
497 #[allow(clippy::too_many_arguments)]
499 pub fn with_op(
500 mut self,
501 op_name: impl Into<String>,
502 clause: impl Fn(String, Box<dyn Fn(String) -> B>) -> B + 'static,
503 ) -> Self {
504 self.op_clauses.insert(op_name.into(), Box::new(clause));
505 self
506 }
507}
508pub struct DelimitedContinuation {
510 pub prompt_type: String,
512}
513impl DelimitedContinuation {
514 pub fn new(prompt_type: impl Into<String>) -> Self {
516 Self {
517 prompt_type: prompt_type.into(),
518 }
519 }
520 pub fn reset(&self) -> String {
522 format!(
523 "reset<{}>: Comp A -> {}",
524 self.prompt_type, self.prompt_type
525 )
526 }
527 pub fn shift(&self) -> String {
529 format!(
530 "shift<{0}>: ((A -> {0}) -> {0}) -> Comp A",
531 self.prompt_type
532 )
533 }
534 pub fn is_first_class(&self) -> bool {
536 true
537 }
538}
539pub struct ContinuationMonad {
541 pub answer_type: String,
543}
544impl ContinuationMonad {
545 pub fn new(answer_type: impl Into<String>) -> Self {
547 Self {
548 answer_type: answer_type.into(),
549 }
550 }
551 pub fn callcc(&self) -> String {
553 format!(
554 "callcc: ((A -> Cont {} B) -> Cont {} A) -> Cont {} A",
555 self.answer_type, self.answer_type, self.answer_type
556 )
557 }
558 pub fn is_monad(&self) -> bool {
560 true
561 }
562 pub fn reset_shift(&self) -> String {
564 format!(
565 "reset: Cont {} {} -> {}; shift: ((A -> {}) -> Cont {} {}) -> Cont {} A",
566 self.answer_type,
567 self.answer_type,
568 self.answer_type,
569 self.answer_type,
570 self.answer_type,
571 self.answer_type,
572 self.answer_type
573 )
574 }
575}
576pub struct ShallowHandler<A, B> {
578 pub effect_name: String,
580 pub val_clause: Box<dyn Fn(A) -> B>,
582 pub op_clause: Box<dyn Fn(String, String, Box<dyn FnOnce(String) -> Free<A>>) -> B>,
584}
585impl<A, B> ShallowHandler<A, B> {
586 pub fn new(
588 effect_name: impl Into<String>,
589 val_clause: impl Fn(A) -> B + 'static,
590 op_clause: impl Fn(String, String, Box<dyn FnOnce(String) -> Free<A>>) -> B + 'static,
591 ) -> Self {
592 ShallowHandler {
593 effect_name: effect_name.into(),
594 val_clause: Box::new(val_clause),
595 op_clause: Box::new(op_clause),
596 }
597 }
598 pub fn handle(self, comp: Free<A>) -> B {
600 match comp {
601 Free::Pure(a) => (self.val_clause)(a),
602 Free::Op { op, arg, cont, .. } => (self.op_clause)(op, arg, cont),
603 }
604 }
605}
606#[derive(Debug, Clone, PartialEq, Eq, Hash)]
608pub struct OpDesc {
609 pub name: String,
611 pub param_ty: String,
613 pub return_ty: String,
615}
616impl OpDesc {
617 pub fn new(name: impl Into<String>, param: impl Into<String>, ret: impl Into<String>) -> Self {
619 OpDesc {
620 name: name.into(),
621 param_ty: param.into(),
622 return_ty: ret.into(),
623 }
624 }
625}
626pub struct Effect {
628 pub name: String,
630 pub operations: Vec<String>,
632}
633impl Effect {
634 pub fn new(name: impl Into<String>, operations: Vec<String>) -> Self {
636 Self {
637 name: name.into(),
638 operations,
639 }
640 }
641 pub fn is_algebraic(&self) -> bool {
643 true
644 }
645 pub fn free_monad(&self) -> String {
647 format!(
648 "Free monad for effect {}: Tree over operations {:?}",
649 self.name, self.operations
650 )
651 }
652}
653pub struct EffectPolymorphism {
655 pub type_vars: Vec<String>,
657 pub effect_vars: Vec<String>,
659}
660impl EffectPolymorphism {
661 pub fn new(type_vars: Vec<String>, effect_vars: Vec<String>) -> Self {
663 Self {
664 type_vars,
665 effect_vars,
666 }
667 }
668 pub fn effect_abstraction(&self) -> String {
670 format!(
671 "Lambda {} . body [abstract over effect rows {:?}]",
672 self.effect_vars.join(", "),
673 self.effect_vars
674 )
675 }
676 pub fn effect_instantiation(&self) -> String {
678 format!(
679 "Inst [{:?} := R] : substitute concrete effect rows for effect vars",
680 self.effect_vars
681 )
682 }
683}
684pub struct DelimCont<A> {
688 body: Box<dyn FnOnce() -> A>,
689}
690impl<A: 'static> DelimCont<A> {
691 pub fn new(body: impl FnOnce() -> A + 'static) -> Self {
693 DelimCont {
694 body: Box::new(body),
695 }
696 }
697 pub fn reset(self) -> A {
699 (self.body)()
700 }
701}
702pub struct EffectRow {
704 pub effects: Vec<String>,
706}
707impl EffectRow {
708 pub fn new(effects: Vec<String>) -> Self {
710 Self { effects }
711 }
712 pub fn is_empty(&self) -> bool {
714 self.effects.is_empty()
715 }
716 pub fn union(&self, other: &EffectRow) -> EffectRow {
718 let mut combined = self.effects.clone();
719 for e in &other.effects {
720 if !combined.contains(e) {
721 combined.push(e.clone());
722 }
723 }
724 EffectRow { effects: combined }
725 }
726 pub fn subtract(&self, effect: &str) -> EffectRow {
728 EffectRow {
729 effects: self
730 .effects
731 .iter()
732 .filter(|e| e.as_str() != effect)
733 .cloned()
734 .collect(),
735 }
736 }
737}
738pub struct EffectInterpreter {
741 handlers: HashMap<String, HashMap<String, Box<dyn Fn(String) -> String>>>,
743}
744impl EffectInterpreter {
745 pub fn new() -> Self {
747 EffectInterpreter {
748 handlers: HashMap::new(),
749 }
750 }
751 pub fn register(
753 mut self,
754 effect: impl Into<String>,
755 op: impl Into<String>,
756 handler: impl Fn(String) -> String + 'static,
757 ) -> Self {
758 self.handlers
759 .entry(effect.into())
760 .or_default()
761 .insert(op.into(), Box::new(handler));
762 self
763 }
764 pub fn run(&self, comp: Free<String>) -> String {
766 match comp {
767 Free::Pure(v) => v,
768 Free::Op {
769 effect,
770 op,
771 arg,
772 cont,
773 } => {
774 if let Some(eff_handlers) = self.handlers.get(&effect) {
775 if let Some(h) = eff_handlers.get(&op) {
776 let result = h(arg);
777 let next = cont(result);
778 self.run(next)
779 } else {
780 format!("unhandled_op({}/{})", effect, op)
781 }
782 } else {
783 format!("unhandled_effect({})", effect)
784 }
785 }
786 }
787 }
788}
789#[allow(dead_code)]
794pub struct GradedMonadImpl<G, A> {
795 pub grade: G,
797 pub value: A,
799}
800#[allow(dead_code)]
801impl<G: Clone + std::fmt::Debug, A: Clone> GradedMonadImpl<G, A> {
802 pub fn unit(grade: G, value: A) -> Self {
804 Self { grade, value }
805 }
806 pub fn map<B, F: Fn(A) -> B>(self, f: F) -> GradedMonadImpl<G, B> {
808 GradedMonadImpl {
809 grade: self.grade,
810 value: f(self.value),
811 }
812 }
813 pub fn grade_description(&self) -> String {
815 format!("Grade: {:?}", self.grade)
816 }
817 pub fn is_unit_grade(&self) -> bool
819 where
820 G: PartialEq + Default,
821 {
822 self.grade == G::default()
823 }
824}
825pub struct EffectInferencer {
829 inferred: HashMap<String, EffRow>,
831}
832impl EffectInferencer {
833 pub fn new() -> Self {
835 EffectInferencer {
836 inferred: HashMap::new(),
837 }
838 }
839 pub fn infer<A>(&mut self, name: impl Into<String>, comp: &Free<A>) -> EffRow {
841 let row = Self::collect_effects(comp);
842 self.inferred.insert(name.into(), row.clone());
843 row
844 }
845 fn collect_effects<A>(comp: &Free<A>) -> EffRow {
846 let mut row = EffRow::empty();
847 Self::collect_rec(comp, &mut row);
848 row
849 }
850 fn collect_rec<A>(comp: &Free<A>, row: &mut EffRow) {
851 match comp {
852 Free::Pure(_) => {}
853 Free::Op { effect, cont, .. } => {
854 row.effects.push(effect.clone());
855 let _ = cont;
856 }
857 }
858 }
859 pub fn get_row(&self, name: &str) -> Option<&EffRow> {
861 self.inferred.get(name)
862 }
863}
864#[allow(dead_code)]
870pub struct EffectPipeline {
871 stages: Vec<(String, String)>,
873}
874#[allow(dead_code)]
875impl EffectPipeline {
876 pub fn new() -> Self {
878 Self { stages: vec![] }
879 }
880 pub fn add_stage(mut self, effect: &str, handler_desc: &str) -> Self {
882 self.stages
883 .push((effect.to_string(), handler_desc.to_string()));
884 self
885 }
886 pub fn depth(&self) -> usize {
888 self.stages.len()
889 }
890 pub fn residual_row(&self, initial: &EffRow) -> EffRow {
893 let mut row = initial.clone();
894 for (eff, _) in &self.stages {
895 row = EffRow {
896 effects: row.effects.into_iter().filter(|e| e != eff).collect(),
897 };
898 }
899 row
900 }
901 pub fn is_complete(&self, initial: &EffRow) -> bool {
903 self.residual_row(initial).is_pure()
904 }
905 pub fn describe(&self) -> String {
907 if self.stages.is_empty() {
908 "Empty pipeline (identity)".to_string()
909 } else {
910 let stage_strs: Vec<String> = self
911 .stages
912 .iter()
913 .map(|(eff, desc)| format!("handle[{}] via {}", eff, desc))
914 .collect();
915 stage_strs.join(" >> ")
916 }
917 }
918 pub fn is_valid_deep_order(&self) -> bool {
920 let mut seen = std::collections::HashSet::new();
921 for (eff, _) in &self.stages {
922 if !seen.insert(eff.clone()) {
923 return false;
924 }
925 }
926 true
927 }
928}
929pub struct FreeMonad {
931 pub functor: String,
933}
934impl FreeMonad {
935 pub fn new(functor: impl Into<String>) -> Self {
937 Self {
938 functor: functor.into(),
939 }
940 }
941 pub fn unit(&self) -> String {
943 format!("return: A -> Free({}) A", self.functor)
944 }
945 pub fn bind(&self) -> String {
947 format!(
948 "bind: Free({0}) A -> (A -> Free({0}) B) -> Free({0}) B",
949 self.functor
950 )
951 }
952 pub fn interpret(&self) -> String {
954 format!(
955 "interpret: (F A -> A) -> Free({}) A -> A [initial algebra morphism]",
956 self.functor
957 )
958 }
959}