Skip to main content

oxilean_std/functional_programming/
types.rs

1//! Auto-generated module
2//!
3//! 🤖 Generated with [SplitRS](https://github.com/cool-japan/splitrs)
4
5use super::functions::*;
6
7/// Futumorphism: anamorphism with look-ahead capability.
8#[allow(dead_code)]
9#[derive(Debug, Clone)]
10pub struct Futumorphism {
11    pub coalgebra_name: String,
12}
13#[allow(dead_code)]
14impl Futumorphism {
15    pub fn new(coalgebra_name: &str) -> Self {
16        Self {
17            coalgebra_name: coalgebra_name.to_string(),
18        }
19    }
20    /// Interleave two lists (futumorphism example).
21    pub fn interleave<A: Clone>(xs: &[A], ys: &[A]) -> Vec<A> {
22        let mut result = Vec::new();
23        for i in 0..xs.len().max(ys.len()) {
24            if i < xs.len() {
25                result.push(xs[i].clone());
26            }
27            if i < ys.len() {
28                result.push(ys[i].clone());
29            }
30        }
31        result
32    }
33}
34/// Defunctionalized closure representation.
35#[allow(dead_code)]
36#[derive(Debug, Clone)]
37pub struct DefunctClosure {
38    pub tag: String,
39    pub free_variables: Vec<(String, String)>,
40    pub apply_case: String,
41}
42#[allow(dead_code)]
43impl DefunctClosure {
44    /// Create a defunctionalized closure.
45    pub fn new(tag: &str, free_vars: Vec<(&str, &str)>, apply: &str) -> Self {
46        Self {
47            tag: tag.to_string(),
48            free_variables: free_vars
49                .iter()
50                .map(|(n, t)| (n.to_string(), t.to_string()))
51                .collect(),
52            apply_case: apply.to_string(),
53        }
54    }
55    /// Arity of the closure (number of captured variables).
56    pub fn arity(&self) -> usize {
57        self.free_variables.len()
58    }
59    /// Apply description.
60    pub fn apply_description(&self) -> String {
61        format!("apply({}) = {}", self.tag, self.apply_case)
62    }
63}
64/// A zipper over a non-empty vector: models a focused list comonad.
65///
66/// The zipper is the canonical comonad for list-like structures:
67/// extract = current element, extend = apply f to each focus position.
68#[derive(Clone)]
69pub struct Zipper<A> {
70    pub left: Vec<A>,
71    pub focus: A,
72    pub right: Vec<A>,
73}
74impl<A: Clone> Zipper<A> {
75    /// Create a zipper focused on index `i` of `data`.
76    ///
77    /// Returns `None` if `data` is empty or `i` is out of bounds.
78    pub fn new(data: Vec<A>, i: usize) -> Option<Self> {
79        if data.is_empty() || i >= data.len() {
80            return None;
81        }
82        let mut v = data;
83        let right = v.split_off(i + 1);
84        let focus = v
85            .pop()
86            .expect("v is non-empty: i < data.len() and v is data[..=i]");
87        Some(Self {
88            left: v,
89            focus,
90            right,
91        })
92    }
93    /// Extract the focused element (counit / extract).
94    pub fn extract(&self) -> &A {
95        &self.focus
96    }
97    /// Extend the zipper comonad: apply `f` at every position.
98    ///
99    /// This implements `extend f w` for the zipper comonad.
100    pub fn extend<B: Clone>(&self, f: impl Fn(&Zipper<A>) -> B) -> Zipper<B> {
101        let all: Vec<A> = self
102            .left
103            .iter()
104            .cloned()
105            .chain(std::iter::once(self.focus.clone()))
106            .chain(self.right.iter().cloned())
107            .collect();
108        let focus_idx = self.left.len();
109        let results: Vec<B> = (0..all.len())
110            .map(|i| {
111                let z = Zipper::new(all.clone(), i)
112                    .expect("i < all.len(): iterating over 0..all.len()");
113                f(&z)
114            })
115            .collect();
116        Zipper::new(results, focus_idx).expect(
117            "focus_idx < results.len(): focus_idx == left.len() < all.len() == results.len()",
118        )
119    }
120    /// Move focus one step to the left.
121    pub fn move_left(&self) -> Option<Zipper<A>> {
122        if self.left.is_empty() {
123            return None;
124        }
125        let mut new_left = self.left.clone();
126        let new_focus = new_left
127            .pop()
128            .expect("new_left is non-empty: left is non-empty, checked by early return");
129        let mut new_right = vec![self.focus.clone()];
130        new_right.extend(self.right.iter().cloned());
131        Some(Zipper {
132            left: new_left,
133            focus: new_focus,
134            right: new_right,
135        })
136    }
137    /// Move focus one step to the right.
138    pub fn move_right(&self) -> Option<Zipper<A>> {
139        if self.right.is_empty() {
140            return None;
141        }
142        let mut new_right = self.right.clone();
143        let new_focus = new_right.remove(0);
144        let mut new_left = self.left.clone();
145        new_left.push(self.focus.clone());
146        Some(Zipper {
147            left: new_left,
148            focus: new_focus,
149            right: new_right,
150        })
151    }
152    /// Collect all elements in order.
153    pub fn to_vec(&self) -> Vec<A> {
154        self.left
155            .iter()
156            .cloned()
157            .chain(std::iter::once(self.focus.clone()))
158            .chain(self.right.iter().cloned())
159            .collect()
160    }
161    /// Length of the full sequence.
162    pub fn len(&self) -> usize {
163        self.left.len() + 1 + self.right.len()
164    }
165    /// A zipper always has at least one element (the focus), so it is never empty.
166    pub fn is_empty(&self) -> bool {
167        false
168    }
169    /// Returns true if the zipper has only one element.
170    pub fn is_singleton(&self) -> bool {
171        self.left.is_empty() && self.right.is_empty()
172    }
173}
174/// Apomorphism: anamorphism with early termination.
175#[allow(dead_code)]
176#[derive(Debug, Clone)]
177pub struct Apomorphism {
178    pub coalgebra_name: String,
179}
180#[allow(dead_code)]
181impl Apomorphism {
182    pub fn new(coalgebra_name: &str) -> Self {
183        Self {
184            coalgebra_name: coalgebra_name.to_string(),
185        }
186    }
187    /// Insert into sorted list as apomorphism.
188    pub fn insert_sorted(mut xs: Vec<i64>, x: i64) -> Vec<i64> {
189        let pos = xs.partition_point(|&v| v <= x);
190        xs.insert(pos, x);
191        xs
192    }
193}
194/// Church encoding utilities for natural numbers.
195#[allow(dead_code)]
196pub struct ChurchNumerals;
197#[allow(dead_code)]
198impl ChurchNumerals {
199    /// Church numeral zero: Λf.Λx. x (conceptual).
200    pub fn church_zero_desc() -> &'static str {
201        "λf. λx. x"
202    }
203    /// Church numeral succ: Λn.Λf.Λx. f (n f x).
204    pub fn church_succ_desc() -> &'static str {
205        "λn. λf. λx. f (n f x)"
206    }
207    /// Convert Church numeral to actual u64 (simulation).
208    pub fn church_to_u64(n: u64) -> u64 {
209        n
210    }
211    /// Church addition: λm.λn.λf.λx. m f (n f x).
212    pub fn church_add(m: u64, n: u64) -> u64 {
213        m + n
214    }
215    /// Church multiplication: λm.λn.λf. m (n f).
216    pub fn church_mul(m: u64, n: u64) -> u64 {
217        m * n
218    }
219    /// Church exponentiation: λm.λn. n m.
220    pub fn church_pow(m: u64, n: u64) -> u64 {
221        m.pow(n as u32)
222    }
223}
224#[allow(dead_code)]
225#[derive(Debug, Clone)]
226pub struct TraversableData {
227    pub container_type: String,
228    pub traverse_type: String,
229    pub is_foldable: bool,
230    pub naturality_condition: String,
231}
232#[allow(dead_code)]
233impl TraversableData {
234    pub fn list_traversable() -> Self {
235        TraversableData {
236            container_type: "List".to_string(),
237            traverse_type: "Applicative f => (a -> f b) -> [a] -> f [b]".to_string(),
238            is_foldable: true,
239            naturality_condition: "t . traverse g = traverse (t . g)".to_string(),
240        }
241    }
242    pub fn map_traversable() -> Self {
243        TraversableData {
244            container_type: "Map k".to_string(),
245            traverse_type: "Applicative f => (a -> f b) -> Map k a -> f (Map k b)".to_string(),
246            is_foldable: true,
247            naturality_condition: "t . traverse g = traverse (t . g)".to_string(),
248        }
249    }
250    pub fn laws(&self) -> Vec<String> {
251        vec![
252            "Naturality: t . traverse f = traverse (t . f) for natural t".to_string(),
253            "Identity: traverse Identity = Identity".to_string(),
254            "Composition: traverse (Compose . fmap g . f) = Compose . fmap (traverse g) . traverse f"
255            .to_string(),
256        ]
257    }
258    pub fn efficient_mapaccum(&self) -> String {
259        format!(
260            "mapAccumL/R for {}: O(n) traversal with accumulated state",
261            self.container_type
262        )
263    }
264}
265/// A traversal focusing on zero or more As inside S.
266pub struct Traversal<S, A> {
267    /// Extract all focused values.
268    to_list: Box<dyn Fn(&S) -> Vec<A>>,
269    /// Reconstruct S from modified values (must have same length as to_list output).
270    from_list: Box<dyn Fn(Vec<A>, &S) -> S>,
271}
272impl<S: 'static + Clone, A: 'static + Clone> Traversal<S, A> {
273    /// Create a traversal from to_list and from_list.
274    pub fn new(
275        to_list: impl Fn(&S) -> Vec<A> + 'static,
276        from_list: impl Fn(Vec<A>, &S) -> S + 'static,
277    ) -> Self {
278        Self {
279            to_list: Box::new(to_list),
280            from_list: Box::new(from_list),
281        }
282    }
283    /// Collect all focused values.
284    pub fn view(&self, s: &S) -> Vec<A> {
285        (self.to_list)(s)
286    }
287    /// Modify all focused values.
288    pub fn over(&self, f: impl Fn(A) -> A, s: S) -> S {
289        let vals: Vec<A> = (self.to_list)(&s).into_iter().map(&f).collect();
290        (self.from_list)(vals, &s)
291    }
292}
293/// `RecursionSchemeEval` provides catamorphism and anamorphism over `RoseTree`.
294pub struct RecursionSchemeEval;
295impl RecursionSchemeEval {
296    /// Catamorphism (fold) over a `RoseTree`.
297    ///
298    /// `alg(a, children_results)` computes the result at each node.
299    pub fn cata<A, B>(tree: RoseTree<A>, alg: &dyn Fn(A, Vec<B>) -> B) -> B {
300        match tree {
301            RoseTree::Node(a, children) => {
302                let results: Vec<B> = children.into_iter().map(|c| Self::cata(c, alg)).collect();
303                alg(a, results)
304            }
305        }
306    }
307    /// Anamorphism (unfold) to produce a `RoseTree` from a seed.
308    ///
309    /// `coalg(seed)` returns `(label, child_seeds)`.
310    pub fn ana<A, S: Clone>(seed: S, coalg: &dyn Fn(S) -> (A, Vec<S>)) -> RoseTree<A> {
311        let (a, children) = coalg(seed);
312        let subtrees = children.into_iter().map(|s| Self::ana(s, coalg)).collect();
313        RoseTree::Node(a, subtrees)
314    }
315    /// Hylomorphism (unfold then fold) without materializing the intermediate tree.
316    pub fn hylo<A, B, S: Clone>(
317        seed: S,
318        coalg: &dyn Fn(S) -> (A, Vec<S>),
319        alg: &dyn Fn(A, Vec<B>) -> B,
320    ) -> B {
321        let (a, children) = coalg(seed);
322        let results: Vec<B> = children
323            .into_iter()
324            .map(|s| Self::hylo(s, coalg, alg))
325            .collect();
326        alg(a, results)
327    }
328}
329/// Paramorphism: catamorphism with access to original sub-trees.
330#[allow(dead_code)]
331#[derive(Debug, Clone)]
332pub struct Paramorphism {
333    pub algebra_name: String,
334}
335#[allow(dead_code)]
336impl Paramorphism {
337    pub fn new(algebra_name: &str) -> Self {
338        Self {
339            algebra_name: algebra_name.to_string(),
340        }
341    }
342    /// Factorial as paramorphism over Nat: para(zero->1, succ(n,acc) -> (n+1)*acc).
343    pub fn factorial_para(n: u64) -> u64 {
344        (1..=n).product()
345    }
346    /// Tails as paramorphism over lists.
347    pub fn tails_para<A: Clone>(xs: &[A]) -> Vec<Vec<A>> {
348        (0..=xs.len()).map(|i| xs[i..].to_vec()).collect()
349    }
350}
351/// Reader monad: Reader r a = r -> a.
352#[allow(dead_code)]
353#[derive(Debug, Clone)]
354pub struct ReaderMonad<R: Clone, A: Clone> {
355    _phantom_r: std::marker::PhantomData<R>,
356    _phantom_a: std::marker::PhantomData<A>,
357    pub description: String,
358}
359#[allow(dead_code)]
360impl<R: Clone, A: Clone> ReaderMonad<R, A> {
361    pub fn new(desc: &str) -> Self {
362        Self {
363            _phantom_r: std::marker::PhantomData,
364            _phantom_a: std::marker::PhantomData,
365            description: desc.to_string(),
366        }
367    }
368    pub fn ask_desc(&self) -> String {
369        format!("ask :: Reader {}", std::any::type_name::<R>())
370    }
371    pub fn local_desc(&self) -> String {
372        format!(
373            "local :: ({0} -> {0}) -> Reader {0} _",
374            std::any::type_name::<R>()
375        )
376    }
377}
378#[allow(dead_code)]
379#[derive(Debug, Clone)]
380pub struct ArrowData {
381    pub arrow_name: String,
382    pub arr_type: String,
383    pub compose_type: String,
384    pub first_type: String,
385    pub is_arrowchoice: bool,
386    pub is_arrowloop: bool,
387}
388#[allow(dead_code)]
389impl ArrowData {
390    pub fn function_arrow() -> Self {
391        ArrowData {
392            arrow_name: "->".to_string(),
393            arr_type: "(b -> c) -> Arrow b c".to_string(),
394            compose_type: "Arrow b c -> Arrow c d -> Arrow b d".to_string(),
395            first_type: "Arrow b c -> Arrow (b, d) (c, d)".to_string(),
396            is_arrowchoice: true,
397            is_arrowloop: true,
398        }
399    }
400    pub fn kleisli_arrow(monad: &str) -> Self {
401        ArrowData {
402            arrow_name: format!("Kleisli {}", monad),
403            arr_type: format!("(b -> {} c) -> Kleisli {} b c", monad, monad),
404            compose_type: format!(
405                "Kleisli {} b c -> Kleisli {} c d -> Kleisli {} b d",
406                monad, monad, monad
407            ),
408            first_type: format!("Kleisli {} b c -> Kleisli {} (b,d) (c,d)", monad, monad),
409            is_arrowchoice: false,
410            is_arrowloop: false,
411        }
412    }
413    pub fn hughes_laws(&self) -> Vec<String> {
414        vec![
415            "arr id = id".to_string(),
416            "arr (f . g) = arr f . arr g".to_string(),
417            "first (arr f) = arr (f *** id)".to_string(),
418            "first (f . g) = first f . first g".to_string(),
419        ]
420    }
421    pub fn freyd_category_connection(&self) -> String {
422        "Arrows generalize Freyd categories (Power-Thielecke): model effectful computations"
423            .to_string()
424    }
425}
426/// A type-erased type-level map (heterogeneous map keyed by strings).
427pub struct HMap {
428    entries: Vec<(String, Box<dyn std::any::Any>)>,
429}
430impl HMap {
431    /// Create an empty HMap.
432    pub fn new() -> Self {
433        Self {
434            entries: Vec::new(),
435        }
436    }
437    /// Insert a key-value pair.
438    pub fn insert<V: 'static>(&mut self, key: impl Into<String>, value: V) {
439        self.entries.push((key.into(), Box::new(value)));
440    }
441    /// Look up a key and downcast.
442    pub fn get<V: 'static>(&self, key: &str) -> Option<&V> {
443        self.entries
444            .iter()
445            .find(|(k, _)| k == key)
446            .and_then(|(_, v)| v.downcast_ref::<V>())
447    }
448    /// Number of entries.
449    pub fn len(&self) -> usize {
450        self.entries.len()
451    }
452    /// Returns true if empty.
453    pub fn is_empty(&self) -> bool {
454        self.entries.is_empty()
455    }
456}
457/// A prism focusing on one variant of a sum type.
458pub struct Prism<S, A> {
459    preview: Box<dyn Fn(S) -> Option<A>>,
460    review: Box<dyn Fn(A) -> S>,
461}
462impl<S: 'static, A: 'static> Prism<S, A> {
463    /// Create a prism from preview and review functions.
464    pub fn new(
465        preview: impl Fn(S) -> Option<A> + 'static,
466        review: impl Fn(A) -> S + 'static,
467    ) -> Self {
468        Self {
469            preview: Box::new(preview),
470            review: Box::new(review),
471        }
472    }
473    /// Try to extract the focused value.
474    pub fn preview(&self, s: S) -> Option<A> {
475        (self.preview)(s)
476    }
477    /// Inject a value into the sum type.
478    pub fn review(&self, a: A) -> S {
479        (self.review)(a)
480    }
481}
482/// A free monad over `ConsoleEffect` for console programs.
483#[allow(dead_code)]
484pub enum ConsoleProg<A> {
485    /// Pure result.
486    Done(A),
487    /// Perform an effect and continue.
488    Step(ConsoleEffect, Box<dyn FnOnce(String) -> ConsoleProg<A>>),
489}
490/// State monad: State s a = s -> (a, s).
491#[allow(dead_code)]
492#[derive(Debug, Clone)]
493pub struct StateMonad<S: Clone, A: Clone> {
494    _phantom_s: std::marker::PhantomData<S>,
495    _phantom_a: std::marker::PhantomData<A>,
496    pub description: String,
497}
498#[allow(dead_code)]
499impl<S: Clone, A: Clone> StateMonad<S, A> {
500    pub fn new(description: &str) -> Self {
501        Self {
502            _phantom_s: std::marker::PhantomData,
503            _phantom_a: std::marker::PhantomData,
504            description: description.to_string(),
505        }
506    }
507    pub fn get_desc(&self) -> String {
508        format!(
509            "get :: State {} {}",
510            std::any::type_name::<S>(),
511            std::any::type_name::<A>()
512        )
513    }
514    pub fn put_desc(&self) -> String {
515        format!(
516            "put :: {} -> State {} ()",
517            std::any::type_name::<S>(),
518            std::any::type_name::<S>()
519        )
520    }
521    pub fn modify_desc(&self) -> String {
522        format!(
523            "modify :: ({0} -> {0}) -> State {0} ()",
524            std::any::type_name::<S>()
525        )
526    }
527}
528#[allow(dead_code)]
529#[derive(Debug, Clone)]
530pub struct DependentTypeExample {
531    pub type_name: String,
532    pub type_signature: String,
533    pub invariant: String,
534    pub language: String,
535}
536#[allow(dead_code)]
537impl DependentTypeExample {
538    pub fn fixed_length_vector(elem_type: &str, n: usize) -> Self {
539        DependentTypeExample {
540            type_name: format!("Vec {} {}", elem_type, n),
541            type_signature: format!("Vec : Type -> ℕ -> Type"),
542            invariant: format!("length is exactly {}", n),
543            language: "Agda/Idris/Lean".to_string(),
544        }
545    }
546    pub fn sorted_list(elem_type: &str) -> Self {
547        DependentTypeExample {
548            type_name: format!("SortedList {}", elem_type),
549            type_signature: "SortedList : Type -> Type".to_string(),
550            invariant: "all elements in sorted order".to_string(),
551            language: "Agda".to_string(),
552        }
553    }
554    pub fn fin_type(n: usize) -> Self {
555        DependentTypeExample {
556            type_name: format!("Fin {}", n),
557            type_signature: "Fin : ℕ -> Type".to_string(),
558            invariant: format!("indices in {{0,..,{}}}", n.saturating_sub(1)),
559            language: "Agda/Lean".to_string(),
560        }
561    }
562    pub fn type_safety_guarantee(&self) -> String {
563        format!(
564            "{}: type system enforces '{}' statically (no runtime check needed)",
565            self.type_name, self.invariant
566        )
567    }
568    pub fn extraction_to_code(&self) -> String {
569        format!(
570            "From {} proof to certified {} code via extraction",
571            self.language, self.language
572        )
573    }
574}
575/// Free applicative functor (simplified representation).
576#[allow(dead_code)]
577#[derive(Debug, Clone)]
578pub enum FreeApplicative<A: Clone> {
579    Pure(A),
580    Ap(usize, Box<FreeApplicative<A>>),
581}
582#[allow(dead_code)]
583impl<A: Clone> FreeApplicative<A> {
584    pub fn pure_val(a: A) -> Self {
585        FreeApplicative::Pure(a)
586    }
587    pub fn depth(&self) -> usize {
588        match self {
589            FreeApplicative::Pure(_) => 0,
590            FreeApplicative::Ap(_, x) => 1 + x.depth(),
591        }
592    }
593}
594/// Histomorphism: catamorphism with access to full history.
595#[allow(dead_code)]
596#[derive(Debug, Clone)]
597pub struct Histomorphism {
598    pub algebra_name: String,
599    pub cache: Vec<i64>,
600}
601#[allow(dead_code)]
602impl Histomorphism {
603    pub fn new(algebra_name: &str) -> Self {
604        Self {
605            algebra_name: algebra_name.to_string(),
606            cache: Vec::new(),
607        }
608    }
609    /// Fibonacci via histomorphism (with memoized history).
610    pub fn fibonacci_histo(&mut self, n: usize) -> i64 {
611        for i in self.cache.len()..=n {
612            let v = if i == 0 {
613                0
614            } else if i == 1 {
615                1
616            } else {
617                self.cache[i - 1] + self.cache[i - 2]
618            };
619            self.cache.push(v);
620        }
621        self.cache[n]
622    }
623}
624/// A simple algebraic effect: a computation that may perform an effect.
625pub enum Effect<E, A> {
626    /// Pure result (no effect)
627    Pure(A),
628    /// Effectful operation with continuation
629    Perform(E, Box<dyn FnOnce(()) -> Effect<E, A>>),
630}
631impl<E: 'static, A: 'static> Effect<E, A> {
632    /// Lift a pure value.
633    pub fn pure(a: A) -> Self {
634        Effect::Pure(a)
635    }
636    /// Handle all effects, collapsing to a pure value.
637    pub fn handle(self, handler: &dyn Fn(E)) -> A
638    where
639        A: Default,
640    {
641        match self {
642            Effect::Pure(a) => a,
643            Effect::Perform(e, k) => {
644                handler(e);
645                k(()).handle(handler)
646            }
647        }
648    }
649}
650/// `ComonadExtend` — utility struct for comonad extension operations.
651pub struct ComonadExtend;
652impl ComonadExtend {
653    /// Run comonadic extension on a zipper.
654    pub fn extend<A: Clone, B: Clone>(z: &Zipper<A>, f: impl Fn(&Zipper<A>) -> B) -> Zipper<B> {
655        z.extend(f)
656    }
657    /// Duplicate: w → W (W a) — the comonad `duplicate`.
658    pub fn duplicate<A: Clone>(z: &Zipper<A>) -> Zipper<Zipper<A>> {
659        z.extend(|sub_z| {
660            let left = sub_z.left.clone();
661            let focus = sub_z.focus.clone();
662            let right = sub_z.right.clone();
663            Zipper { left, focus, right }
664        })
665    }
666}
667/// Hylomorphism: unfold an anamorphism then fold a catamorphism.
668#[allow(dead_code)]
669#[derive(Debug, Clone)]
670pub struct Hylomorphism {
671    pub seed_label: String,
672    pub unfold_steps: Vec<String>,
673    pub fold_steps: Vec<String>,
674}
675#[allow(dead_code)]
676impl Hylomorphism {
677    pub fn new(seed_label: &str) -> Self {
678        Self {
679            seed_label: seed_label.to_string(),
680            unfold_steps: Vec::new(),
681            fold_steps: Vec::new(),
682        }
683    }
684    pub fn add_unfold_step(mut self, step: &str) -> Self {
685        self.unfold_steps.push(step.to_string());
686        self
687    }
688    pub fn add_fold_step(mut self, step: &str) -> Self {
689        self.fold_steps.push(step.to_string());
690        self
691    }
692    /// Fibonacci as hylomorphism: ana unfolds to tree of additions, cata folds.
693    pub fn fibonacci_hylo(n: u32) -> u64 {
694        fn fib(n: u32) -> u64 {
695            if n <= 1 {
696                return n as u64;
697            }
698            let mut a = 0u64;
699            let mut b = 1u64;
700            for _ in 2..=n {
701                let c = a + b;
702                a = b;
703                b = c;
704            }
705            b
706        }
707        fib(n)
708    }
709}
710/// Algebraic effect system.
711#[allow(dead_code)]
712#[derive(Debug, Clone)]
713pub struct EffectSystem {
714    pub effect_name: String,
715    pub operations: Vec<(String, String)>,
716    pub handler_type: String,
717}
718#[allow(dead_code)]
719impl EffectSystem {
720    /// State effect.
721    pub fn state(state_type: &str) -> Self {
722        Self {
723            effect_name: format!("State({})", state_type),
724            operations: vec![
725                ("get".to_string(), format!("unit -> {}", state_type)),
726                ("put".to_string(), format!("{} -> unit", state_type)),
727            ],
728            handler_type: format!("{} -> a -> ({} * {})", state_type, state_type, "a"),
729        }
730    }
731    /// Exception effect.
732    pub fn exception(exc_type: &str) -> Self {
733        Self {
734            effect_name: format!("Exception({})", exc_type),
735            operations: vec![("throw".to_string(), format!("{} -> a", exc_type))],
736            handler_type: format!("({} -> b) -> (a -> b) -> b", exc_type),
737        }
738    }
739    /// Number of operations.
740    pub fn num_ops(&self) -> usize {
741        self.operations.len()
742    }
743}
744/// A profunctor-encoded optic, represented as a Rust trait object.
745///
746/// In Haskell: `type Optic p s t a b = p a b -> p s t`.
747/// Here we use `Fn(Box<dyn Fn(a) -> b>) -> Box<dyn Fn(s) -> t>` as a simplified model.
748pub struct ProfunctorOptic<S, T, A, B> {
749    run: Box<dyn Fn(Box<dyn Fn(A) -> B>) -> Box<dyn Fn(S) -> T>>,
750}
751impl<S: 'static, T: 'static, A: 'static, B: 'static> ProfunctorOptic<S, T, A, B> {
752    /// Construct a profunctor optic from an adapter function.
753    pub fn new(run: impl Fn(Box<dyn Fn(A) -> B>) -> Box<dyn Fn(S) -> T> + 'static) -> Self {
754        Self { run: Box::new(run) }
755    }
756    /// Apply the optic to a concrete mapping function.
757    pub fn apply(&self, f: impl Fn(A) -> B + 'static) -> Box<dyn Fn(S) -> T> {
758        (self.run)(Box::new(f))
759    }
760    /// Build a simple lens-style profunctor optic from getter and setter.
761    pub fn lens_optic(
762        getter: impl Fn(&S) -> A + 'static,
763        setter: impl Fn(B, S) -> T + 'static,
764    ) -> Self
765    where
766        S: Clone + 'static,
767    {
768        let getter = std::sync::Arc::new(getter);
769        let setter = std::sync::Arc::new(setter);
770        Self::new(move |f: Box<dyn Fn(A) -> B>| {
771            let getter = getter.clone();
772            let setter = setter.clone();
773            let f = std::sync::Arc::new(f);
774            Box::new(move |s: S| {
775                let a = getter(&s);
776                let b = f(a);
777                setter(b, s)
778            })
779        })
780    }
781    /// Build a prism-style profunctor optic from preview and review.
782    pub fn prism_optic(
783        preview: impl Fn(S) -> Result<A, T> + 'static,
784        review: impl Fn(B) -> T + 'static,
785    ) -> Self
786    where
787        S: 'static,
788    {
789        let preview = std::sync::Arc::new(preview);
790        let review = std::sync::Arc::new(review);
791        Self::new(move |f: Box<dyn Fn(A) -> B>| {
792            let preview = preview.clone();
793            let review = review.clone();
794            let f = std::sync::Arc::new(f);
795            Box::new(move |s: S| match preview(s) {
796                Ok(a) => review(f(a)),
797                Err(t) => t,
798            })
799        })
800    }
801}
802/// A heterogeneous list (type-erased at runtime; type safety tracked by the user).
803pub enum HList {
804    /// The empty HList
805    Nil,
806    /// A cons cell holding a boxed value and the tail
807    Cons(Box<dyn std::any::Any>, Box<HList>),
808}
809impl HList {
810    /// The empty heterogeneous list.
811    pub fn nil() -> Self {
812        HList::Nil
813    }
814    /// Prepend any value to the HList.
815    pub fn cons<T: 'static>(head: T, tail: HList) -> Self {
816        HList::Cons(Box::new(head), Box::new(tail))
817    }
818    /// Returns the length of this HList.
819    pub fn len(&self) -> usize {
820        match self {
821            HList::Nil => 0,
822            HList::Cons(_, tail) => 1 + tail.len(),
823        }
824    }
825    /// Returns true if this HList is empty.
826    pub fn is_empty(&self) -> bool {
827        matches!(self, HList::Nil)
828    }
829}
830/// Evaluator for generic recursion schemes over rose trees.
831///
832/// A `RoseTree<A>` models the fixed point of F X = A × List X.
833#[allow(dead_code)]
834pub enum RoseTree<A> {
835    /// A leaf/node with a value and zero or more children.
836    Node(A, Vec<RoseTree<A>>),
837}
838/// Type equality evidence: proof that S and T are the same type.
839pub struct TypeEquality<S, T> {
840    _coerce: std::marker::PhantomData<(S, T)>,
841}
842impl<T> TypeEquality<T, T> {
843    /// Reflexivity: every type is equal to itself.
844    pub fn refl() -> Self {
845        TypeEquality {
846            _coerce: std::marker::PhantomData,
847        }
848    }
849}
850impl<S, T> TypeEquality<S, T> {
851    /// Use type equality evidence to coerce a value.
852    pub fn coerce(self, s: S) -> T
853    where
854        S: Into<T>,
855    {
856        s.into()
857    }
858}
859/// `LensComposer` provides utilities for composing lenses and verifying laws.
860pub struct LensComposer;
861impl LensComposer {
862    /// Compose two lenses: `outer` focuses on `M` inside `S`,
863    /// `inner` focuses on `A` inside `M`.
864    pub fn compose<S, M, A>(outer: Lens<S, M>, inner: Lens<M, A>) -> impl Fn(&S) -> A
865    where
866        S: Clone + 'static,
867        M: Clone + 'static,
868        A: Clone + 'static,
869    {
870        move |s: &S| {
871            let m = outer.view(s);
872            inner.view(&m)
873        }
874    }
875    /// Check the GetSet law: `set(get(s), s) == s`.
876    pub fn check_get_set<S, A>(lens: &Lens<S, A>, s: S) -> bool
877    where
878        S: Clone + PartialEq + 'static,
879        A: Clone + 'static,
880    {
881        let a = lens.view(&s);
882        let s2 = lens.set(a, s.clone());
883        s2 == s
884    }
885    /// Check the SetGet law: `get(set(a, s)) == a`.
886    pub fn check_set_get<S, A>(lens: &Lens<S, A>, a: A, s: S) -> bool
887    where
888        S: Clone + 'static,
889        A: Clone + PartialEq + 'static,
890    {
891        let s2 = lens.set(a.clone(), s);
892        let a2 = lens.view(&s2);
893        a2 == a
894    }
895    /// Check the SetSet law: `set(a2, set(a1, s)) == set(a2, s)`.
896    pub fn check_set_set<S, A>(lens: &Lens<S, A>, a1: A, a2: A, s: S) -> bool
897    where
898        S: Clone + PartialEq + 'static,
899        A: Clone + 'static,
900    {
901        let s_after_a1 = lens.set(a1, s.clone());
902        let s_after_a2_a1 = lens.set(a2.clone(), s_after_a1);
903        let s_after_a2 = lens.set(a2, s);
904        s_after_a2_a1 == s_after_a2
905    }
906}
907/// A coercion with a proof obligation (modelled as a runtime-checked cast).
908pub struct Coerce<S, T> {
909    _marker: std::marker::PhantomData<(S, T)>,
910}
911impl<S: 'static, T: 'static> Coerce<S, T> {
912    /// Attempt to coerce using Any downcast; returns None if types differ.
913    pub fn try_coerce(s: S) -> Option<T> {
914        let boxed: Box<dyn std::any::Any> = Box::new(s);
915        boxed.downcast::<T>().ok().map(|b| *b)
916    }
917}
918/// Free monad functor encoding.
919#[allow(dead_code)]
920#[derive(Debug, Clone)]
921pub struct FreeMonadInfo {
922    pub functor_name: String,
923    pub operations: Vec<String>,
924    pub description: String,
925}
926#[allow(dead_code)]
927impl FreeMonadInfo {
928    /// Free monad over a functor F.
929    pub fn over(functor: &str, ops: Vec<&str>) -> Self {
930        Self {
931            functor_name: functor.to_string(),
932            operations: ops.iter().map(|s| s.to_string()).collect(),
933            description: format!("Free monad over {} with {} operations", functor, ops.len()),
934        }
935    }
936    /// Interpretation via fold.
937    pub fn interpreter_description(&self) -> String {
938        format!(
939            "foldFree :: ({} a -> m a) -> Free {} a -> m a",
940            self.functor_name, self.functor_name
941        )
942    }
943    /// Number of operations.
944    pub fn num_operations(&self) -> usize {
945        self.operations.len()
946    }
947}
948/// Continuation passing style transform.
949#[allow(dead_code)]
950#[derive(Debug, Clone)]
951pub struct CpsTransform {
952    pub source_type: String,
953    pub result_type: String,
954    pub continuation_type: String,
955}
956#[allow(dead_code)]
957impl CpsTransform {
958    /// CPS transform A with result R.
959    pub fn new(source: &str, result: &str) -> Self {
960        Self {
961            source_type: source.to_string(),
962            result_type: result.to_string(),
963            continuation_type: format!("({} -> {}) -> {}", source, result, result),
964        }
965    }
966    /// Direct style to CPS description.
967    pub fn transform_description(&self) -> String {
968        format!("CPS[{}] = ({})", self.source_type, self.continuation_type)
969    }
970}
971/// Scott encoding of algebraic data types.
972#[allow(dead_code)]
973pub struct ScottEncoding;
974#[allow(dead_code)]
975impl ScottEncoding {
976    /// Scott-encoded Boolean: True = λt. λf. t; False = λt. λf. f.
977    pub fn scott_true_desc() -> &'static str {
978        "λt. λf. t"
979    }
980    pub fn scott_false_desc() -> &'static str {
981        "λt. λf. f"
982    }
983    /// Scott-encoded pair: Pair a b = λs. s a b.
984    pub fn scott_pair_desc() -> &'static str {
985        "λa. λb. λs. s a b"
986    }
987    /// Scott-encoded fst: fst p = p (λa. λb. a).
988    pub fn scott_fst_desc() -> &'static str {
989        "λp. p (λa. λb. a)"
990    }
991    /// Scott-encoded List: Nil = λn. λc. n; Cons h t = λn. λc. c h t.
992    pub fn scott_nil_desc() -> &'static str {
993        "λn. λc. n"
994    }
995    pub fn scott_cons_desc() -> &'static str {
996        "λh. λt. λn. λc. c h t"
997    }
998}
999/// A lawful lens focusing on field A inside structure S.
1000pub struct Lens<S, A> {
1001    getter: Box<dyn Fn(&S) -> A>,
1002    setter: Box<dyn Fn(A, S) -> S>,
1003}
1004impl<S: 'static, A: 'static> Lens<S, A> {
1005    /// Create a lens from a getter and a setter.
1006    pub fn new(getter: impl Fn(&S) -> A + 'static, setter: impl Fn(A, S) -> S + 'static) -> Self {
1007        Self {
1008            getter: Box::new(getter),
1009            setter: Box::new(setter),
1010        }
1011    }
1012    /// Get the focused value.
1013    pub fn view(&self, s: &S) -> A {
1014        (self.getter)(s)
1015    }
1016    /// Set the focused value.
1017    pub fn set(&self, a: A, s: S) -> S {
1018        (self.setter)(a, s)
1019    }
1020    /// Modify the focused value.
1021    pub fn over(&self, f: impl Fn(A) -> A, s: S) -> S
1022    where
1023        S: Clone,
1024    {
1025        let a = self.view(&s);
1026        self.set(f(a), s)
1027    }
1028}
1029/// Böhm-Berarducci (CPS) encoding of recursive types.
1030#[allow(dead_code)]
1031pub struct BoehmBerarducci;
1032#[allow(dead_code)]
1033impl BoehmBerarducci {
1034    /// BB-encoded natural number as higher-rank type.
1035    pub fn bb_nat_type_desc() -> &'static str {
1036        "forall r. r -> (r -> r) -> r"
1037    }
1038    /// BB-encoded list: List a = forall r. r -> (a -> r -> r) -> r.
1039    pub fn bb_list_type_desc() -> &'static str {
1040        "forall r. r -> (a -> r -> r) -> r"
1041    }
1042    /// BB-encoded rose tree: Tree a = forall r. (a -> List r -> r) -> r.
1043    pub fn bb_tree_type_desc() -> &'static str {
1044        "forall r. (a -> List r -> r) -> r"
1045    }
1046}
1047/// An isomorphism between types S and A.
1048pub struct Iso<S, A> {
1049    to: Box<dyn Fn(S) -> A>,
1050    from: Box<dyn Fn(A) -> S>,
1051}
1052impl<S: 'static, A: 'static> Iso<S, A> {
1053    /// Create an iso from to/from functions.
1054    pub fn new(to: impl Fn(S) -> A + 'static, from: impl Fn(A) -> S + 'static) -> Self {
1055        Self {
1056            to: Box::new(to),
1057            from: Box::new(from),
1058        }
1059    }
1060    /// Apply the forward direction.
1061    pub fn view(&self, s: S) -> A {
1062        (self.to)(s)
1063    }
1064    /// Apply the reverse direction.
1065    pub fn review(&self, a: A) -> S {
1066        (self.from)(a)
1067    }
1068    /// Use this iso as a lens: get.
1069    pub fn get(&self, s: S) -> A {
1070        (self.to)(s)
1071    }
1072}
1073/// An effect handler that handles effect type E and produces B.
1074pub struct EffectHandler<E, A, B> {
1075    handle_fn: Box<dyn Fn(E, Box<dyn FnOnce(A) -> B>) -> B>,
1076}
1077impl<E: 'static, A: 'static, B: 'static> EffectHandler<E, A, B> {
1078    /// Create a handler.
1079    pub fn new(handle_fn: impl Fn(E, Box<dyn FnOnce(A) -> B>) -> B + 'static) -> Self {
1080        Self {
1081            handle_fn: Box::new(handle_fn),
1082        }
1083    }
1084    /// Run the handler on an effect with a continuation.
1085    pub fn run(&self, effect: E, continuation: impl FnOnce(A) -> B + 'static) -> B {
1086        (self.handle_fn)(effect, Box::new(continuation))
1087    }
1088}
1089/// Yoneda lemma embedding: Hom(A, -) ≅ F where F is a functor.
1090#[allow(dead_code)]
1091#[derive(Debug, Clone)]
1092pub struct YonedaEmbedding<A: Clone> {
1093    pub object: A,
1094    pub morphism_count: usize,
1095}
1096#[allow(dead_code)]
1097impl<A: Clone> YonedaEmbedding<A> {
1098    pub fn new(object: A) -> Self {
1099        Self {
1100            object,
1101            morphism_count: 0,
1102        }
1103    }
1104    /// Register a morphism (conceptually). Returns updated count.
1105    pub fn add_morphism(mut self) -> Self {
1106        self.morphism_count += 1;
1107        self
1108    }
1109}
1110#[allow(dead_code)]
1111#[derive(Debug, Clone)]
1112pub struct HomotopyEquivalence {
1113    pub type_a: String,
1114    pub type_b: String,
1115    pub forth_map: String,
1116    pub back_map: String,
1117    pub is_univalent: bool,
1118}
1119#[allow(dead_code)]
1120impl HomotopyEquivalence {
1121    pub fn new(a: &str, b: &str, f: &str, g: &str) -> Self {
1122        HomotopyEquivalence {
1123            type_a: a.to_string(),
1124            type_b: b.to_string(),
1125            forth_map: f.to_string(),
1126            back_map: g.to_string(),
1127            is_univalent: false,
1128        }
1129    }
1130    pub fn univalent_equivalence(mut self) -> Self {
1131        self.is_univalent = true;
1132        self
1133    }
1134    pub fn contractibility_condition(&self) -> String {
1135        format!(
1136            "{} ≃ {}: ∃ f:{}->{}, g:{}->{}, f∘g∼id, g∘f∼id",
1137            self.type_a, self.type_b, self.type_a, self.type_b, self.type_b, self.type_a
1138        )
1139    }
1140    pub fn univalence_axiom(&self) -> String {
1141        if self.is_univalent {
1142            "(A=B) ≃ (A≃B) (Voevodsky's univalence axiom)".to_string()
1143        } else {
1144            "Not using univalence axiom".to_string()
1145        }
1146    }
1147}
1148/// Continuation monad: Cont r a = (a -> r) -> r.
1149#[allow(dead_code)]
1150#[derive(Debug, Clone)]
1151pub struct Cont<R: Clone, A: Clone> {
1152    _phantom_r: std::marker::PhantomData<R>,
1153    _phantom_a: std::marker::PhantomData<A>,
1154    pub label: String,
1155}
1156#[allow(dead_code)]
1157impl<R: Clone, A: Clone> Cont<R, A> {
1158    pub fn new(label: &str) -> Self {
1159        Self {
1160            _phantom_r: std::marker::PhantomData,
1161            _phantom_a: std::marker::PhantomData,
1162            label: label.to_string(),
1163        }
1164    }
1165    /// run_cont :: Cont r a -> (a -> r) -> r (represented symbolically).
1166    pub fn run_cont_desc(&self) -> String {
1167        format!("Cont({}).run_cont", self.label)
1168    }
1169}
1170/// A free monad over a functor F, with values in A.
1171pub enum FreeMonad<A> {
1172    /// The pure/return constructor
1173    Pure(A),
1174    /// The free/join constructor wrapping a functor layer
1175    Free(Box<dyn FnOnce() -> FreeMonad<A>>),
1176}
1177impl<A> FreeMonad<A> {
1178    /// Lift a pure value into the free monad.
1179    pub fn pure(a: A) -> Self {
1180        FreeMonad::Pure(a)
1181    }
1182    /// Fold (catamorphism) over the free monad.
1183    pub fn fold<B>(self, pure_fn: impl Fn(A) -> B, free_fn: impl Fn(FreeMonad<A>) -> B) -> B {
1184        match self {
1185            FreeMonad::Pure(a) => pure_fn(a),
1186            FreeMonad::Free(mk) => free_fn(mk()),
1187        }
1188    }
1189}
1190/// A simple algebraic effect for the interpreter.
1191#[allow(dead_code)]
1192pub enum ConsoleEffect {
1193    /// Print a string to the console.
1194    Print(String),
1195    /// Read a line (returns a constant in tests).
1196    Read,
1197}
1198/// `FreeMonadInterpreter` runs a `ConsoleProg` against a provided handler.
1199pub struct FreeMonadInterpreter;
1200impl FreeMonadInterpreter {
1201    /// Interpret a `ConsoleProg` using provided print/read handlers.
1202    pub fn run<A>(
1203        prog: ConsoleProg<A>,
1204        print_handler: &mut dyn FnMut(&str),
1205        read_handler: &mut dyn FnMut() -> String,
1206    ) -> A {
1207        match prog {
1208            ConsoleProg::Done(a) => a,
1209            ConsoleProg::Step(effect, k) => match effect {
1210                ConsoleEffect::Print(msg) => {
1211                    print_handler(&msg);
1212                    Self::run(k(String::new()), print_handler, read_handler)
1213                }
1214                ConsoleEffect::Read => {
1215                    let line = read_handler();
1216                    Self::run(k(line), print_handler, read_handler)
1217                }
1218            },
1219        }
1220    }
1221}
1222/// Category theory view: functors as type constructors.
1223#[allow(dead_code)]
1224#[derive(Debug, Clone)]
1225pub struct TypeConstructorFunctor {
1226    pub name: String,
1227    pub fmap_type: String,
1228    pub laws: Vec<String>,
1229}
1230#[allow(dead_code)]
1231impl TypeConstructorFunctor {
1232    /// List functor.
1233    pub fn list() -> Self {
1234        Self {
1235            name: "List".to_string(),
1236            fmap_type: "(a -> b) -> List a -> List b".to_string(),
1237            laws: vec![
1238                "fmap id = id".to_string(),
1239                "fmap (f . g) = fmap f . fmap g".to_string(),
1240            ],
1241        }
1242    }
1243    /// Maybe functor.
1244    pub fn maybe() -> Self {
1245        Self {
1246            name: "Maybe".to_string(),
1247            fmap_type: "(a -> b) -> Maybe a -> Maybe b".to_string(),
1248            laws: vec![
1249                "fmap id = id".to_string(),
1250                "fmap (f . g) = fmap f . fmap g".to_string(),
1251            ],
1252        }
1253    }
1254    /// Number of laws.
1255    pub fn num_laws(&self) -> usize {
1256        self.laws.len()
1257    }
1258}
1259#[allow(dead_code)]
1260#[derive(Debug, Clone)]
1261pub struct ProfunctorData {
1262    pub profunctor_name: String,
1263    pub dimap_type: String,
1264    pub is_cartesian: bool,
1265    pub is_cocartesian: bool,
1266    pub is_closed: bool,
1267}
1268#[allow(dead_code)]
1269impl ProfunctorData {
1270    pub fn function_profunctor() -> Self {
1271        ProfunctorData {
1272            profunctor_name: "(->)".to_string(),
1273            dimap_type: "(a -> b) -> (c -> d) -> (b -> c) -> (a -> d)".to_string(),
1274            is_cartesian: true,
1275            is_cocartesian: true,
1276            is_closed: true,
1277        }
1278    }
1279    pub fn star_profunctor(functor: &str) -> Self {
1280        ProfunctorData {
1281            profunctor_name: format!("Star {}", functor),
1282            dimap_type: format!(
1283                "(a -> b) -> (c -> d) -> (b -> {} c) -> (a -> {} d)",
1284                functor, functor
1285            ),
1286            is_cartesian: true,
1287            is_cocartesian: false,
1288            is_closed: false,
1289        }
1290    }
1291    pub fn optic_encoding(&self) -> String {
1292        "Profunctor optics: Lens = ∀p. Cartesian p => p a b -> p s t".to_string()
1293    }
1294    pub fn tambara_module_connection(&self) -> String {
1295        "Tambara module: profunctor P with strength α: P a b -> P (c,a) (c,b)".to_string()
1296    }
1297    pub fn bartosz_milewski_connection(&self) -> String {
1298        "Milewski: profunctors and optics in category theory for programmers".to_string()
1299    }
1300}
1301/// A singleton: a value that is uniquely determined by its type.
1302pub struct Singleton<T> {
1303    /// The unique value
1304    pub value: T,
1305}
1306impl<T: Clone> Singleton<T> {
1307    /// Create a singleton.
1308    pub fn new(value: T) -> Self {
1309        Self { value }
1310    }
1311    /// Extract the value.
1312    pub fn extract(&self) -> T {
1313        self.value.clone()
1314    }
1315}
1316/// An Arrow: a generalised function from A to B with category operations.
1317pub struct Arrow<A, B> {
1318    run: Box<dyn Fn(A) -> B>,
1319}
1320impl<A: 'static, B: 'static> Arrow<A, B> {
1321    /// Lift a plain function into an Arrow.
1322    pub fn arr(f: impl Fn(A) -> B + 'static) -> Self {
1323        Self { run: Box::new(f) }
1324    }
1325    /// Apply the arrow.
1326    pub fn apply(&self, a: A) -> B {
1327        (self.run)(a)
1328    }
1329    /// Compose two arrows.
1330    pub fn compose<C: 'static>(self, other: Arrow<B, C>) -> Arrow<A, C> {
1331        Arrow::arr(move |a| other.apply(self.apply(a)))
1332    }
1333}
1334/// An affine traversal (0 or 1 focus).
1335pub struct AffineTraversal<S, A> {
1336    preview: Box<dyn Fn(&S) -> Option<A>>,
1337    set: Box<dyn Fn(A, S) -> S>,
1338}
1339impl<S: 'static, A: 'static> AffineTraversal<S, A> {
1340    /// Create an affine traversal.
1341    pub fn new(
1342        preview: impl Fn(&S) -> Option<A> + 'static,
1343        set: impl Fn(A, S) -> S + 'static,
1344    ) -> Self {
1345        Self {
1346            preview: Box::new(preview),
1347            set: Box::new(set),
1348        }
1349    }
1350    /// Preview the focus.
1351    pub fn preview(&self, s: &S) -> Option<A> {
1352        (self.preview)(s)
1353    }
1354    /// Set the focus if present.
1355    pub fn set(&self, a: A, s: S) -> S {
1356        (self.set)(a, s)
1357    }
1358}
1359/// Writer monad: Writer w a = (a, w) with Monoid w.
1360#[allow(dead_code)]
1361#[derive(Debug, Clone)]
1362pub struct WriterMonad<A: Clone> {
1363    pub value: A,
1364    pub log: Vec<String>,
1365}
1366#[allow(dead_code)]
1367impl<A: Clone> WriterMonad<A> {
1368    pub fn new(value: A) -> Self {
1369        Self {
1370            value,
1371            log: Vec::new(),
1372        }
1373    }
1374    pub fn tell(mut self, msg: String) -> Self {
1375        self.log.push(msg);
1376        self
1377    }
1378    pub fn listen(&self) -> (&A, &Vec<String>) {
1379        (&self.value, &self.log)
1380    }
1381    pub fn pass<F: Fn(&Vec<String>) -> Vec<String>>(mut self, f: F) -> Self {
1382        self.log = f(&self.log);
1383        self
1384    }
1385}
1386#[allow(dead_code)]
1387#[derive(Debug, Clone)]
1388pub struct ApplicativeData {
1389    pub functor_name: String,
1390    pub pure_type: String,
1391    pub ap_type: String,
1392    pub is_monad: bool,
1393}
1394#[allow(dead_code)]
1395impl ApplicativeData {
1396    pub fn new(name: &str, pure_ty: &str, ap_ty: &str, monad: bool) -> Self {
1397        ApplicativeData {
1398            functor_name: name.to_string(),
1399            pure_type: pure_ty.to_string(),
1400            ap_type: ap_ty.to_string(),
1401            is_monad: monad,
1402        }
1403    }
1404    pub fn maybe_applicative() -> Self {
1405        ApplicativeData {
1406            functor_name: "Maybe".to_string(),
1407            pure_type: "a -> Maybe a".to_string(),
1408            ap_type: "Maybe (a -> b) -> Maybe a -> Maybe b".to_string(),
1409            is_monad: true,
1410        }
1411    }
1412    pub fn validation_applicative() -> Self {
1413        ApplicativeData {
1414            functor_name: "Validation e".to_string(),
1415            pure_type: "a -> Validation e a".to_string(),
1416            ap_type: "Validation e (a -> b) -> Validation e a -> Validation e b".to_string(),
1417            is_monad: false,
1418        }
1419    }
1420    pub fn laws(&self) -> Vec<String> {
1421        vec![
1422            "Identity: pure id <*> v = v".to_string(),
1423            "Composition: pure (.) <*> u <*> v <*> w = u <*> (v <*> w)".to_string(),
1424            "Homomorphism: pure f <*> pure x = pure (f x)".to_string(),
1425            "Interchange: u <*> pure y = pure ($ y) <*> u".to_string(),
1426        ]
1427    }
1428    pub fn mcbride_paterson_paper(&self) -> String {
1429        "McBride-Paterson (2008): Applicative programming with effects".to_string()
1430    }
1431}