Skip to main content

oxilean_std/functor/
functions.rs

1//! Auto-generated module
2//!
3//! 🤖 Generated with [SplitRS](https://github.com/cool-japan/splitrs)
4
5use oxilean_kernel::{BinderInfo, Declaration, Environment, Expr, Level, Name};
6
7use super::types::{
8    Either, OptionFunctor, Pred, Reader, RepresentableFunctorExt, ResultFunctor, VecFunctor, Writer,
9};
10
11/// Build Functor type class in the environment.
12pub fn build_functor_env(env: &mut Environment) -> Result<(), String> {
13    let type1 = Expr::Sort(Level::succ(Level::zero()));
14    let type2 = Expr::Sort(Level::succ(Level::succ(Level::zero())));
15    let functor_ty = Expr::Pi(
16        BinderInfo::Default,
17        Name::str("f"),
18        Box::new(Expr::Pi(
19            BinderInfo::Default,
20            Name::str("_"),
21            Box::new(type1.clone()),
22            Box::new(type1.clone()),
23        )),
24        Box::new(type2.clone()),
25    );
26    env.add(Declaration::Axiom {
27        name: Name::str("Functor"),
28        univ_params: vec![],
29        ty: functor_ty,
30    })
31    .map_err(|e| e.to_string())?;
32    let map_ty = Expr::Pi(
33        BinderInfo::Implicit,
34        Name::str("f"),
35        Box::new(Expr::Pi(
36            BinderInfo::Default,
37            Name::str("_"),
38            Box::new(type1.clone()),
39            Box::new(type1.clone()),
40        )),
41        Box::new(Expr::Pi(
42            BinderInfo::InstImplicit,
43            Name::str("_"),
44            Box::new(Expr::App(
45                Box::new(Expr::Const(Name::str("Functor"), vec![])),
46                Box::new(Expr::BVar(0)),
47            )),
48            Box::new(Expr::Pi(
49                BinderInfo::Implicit,
50                Name::str("a"),
51                Box::new(type1.clone()),
52                Box::new(Expr::Pi(
53                    BinderInfo::Implicit,
54                    Name::str("b"),
55                    Box::new(type1.clone()),
56                    Box::new(Expr::Pi(
57                        BinderInfo::Default,
58                        Name::str("fn"),
59                        Box::new(Expr::Pi(
60                            BinderInfo::Default,
61                            Name::str("_"),
62                            Box::new(Expr::BVar(1)),
63                            Box::new(Expr::BVar(1)),
64                        )),
65                        Box::new(Expr::Pi(
66                            BinderInfo::Default,
67                            Name::str("fa"),
68                            Box::new(Expr::App(Box::new(Expr::BVar(4)), Box::new(Expr::BVar(2)))),
69                            Box::new(Expr::App(Box::new(Expr::BVar(5)), Box::new(Expr::BVar(2)))),
70                        )),
71                    )),
72                )),
73            )),
74        )),
75    );
76    env.add(Declaration::Axiom {
77        name: Name::str("Functor.map"),
78        univ_params: vec![],
79        ty: map_ty,
80    })
81    .map_err(|e| e.to_string())?;
82    Ok(())
83}
84/// Build mapConst in the environment.
85pub fn build_functor_map_const(env: &mut Environment) -> Result<(), String> {
86    let type1 = Expr::Sort(Level::succ(Level::zero()));
87    let ty = Expr::Pi(
88        BinderInfo::Default,
89        Name::str("_"),
90        Box::new(type1.clone()),
91        Box::new(type1),
92    );
93    env.add(Declaration::Axiom {
94        name: Name::str("Functor.mapConst"),
95        univ_params: vec![],
96        ty,
97    })
98    .map_err(|e| e.to_string())
99}
100/// Register all Functor declarations.
101pub fn build_all_functor_decls(env: &mut Environment) -> Result<(), String> {
102    build_functor_env(env)?;
103    build_functor_map_const(env)?;
104    Ok(())
105}
106/// Rust-level Functor trait.
107pub trait Functor<A> {
108    /// The mapped-over container type.
109    type Mapped<B>;
110    /// Apply f to every element.
111    fn fmap<B, F: Fn(A) -> B>(self, f: F) -> Self::Mapped<B>;
112}
113/// Lift f over Option<A>.
114pub fn fmap_option<A, B, F: Fn(A) -> B>(opt: Option<A>, f: F) -> Option<B> {
115    opt.map(f)
116}
117/// Lift f over Vec<A>.
118pub fn fmap_vec<A, B, F: Fn(A) -> B>(v: Vec<A>, f: F) -> Vec<B> {
119    v.into_iter().map(f).collect()
120}
121/// Lift f over Result<A, E>.
122pub fn fmap_result<A, B, E, F: Fn(A) -> B>(r: Result<A, E>, f: F) -> Result<B, E> {
123    r.map(f)
124}
125/// Build a fmap application expression.
126pub fn make_fmap_expr(f_ty: Expr, map_fn: Expr, fa: Expr) -> Expr {
127    Expr::App(
128        Box::new(Expr::App(
129            Box::new(Expr::App(
130                Box::new(Expr::Const(Name::str("Functor.map"), vec![])),
131                Box::new(f_ty),
132            )),
133            Box::new(map_fn),
134        )),
135        Box::new(fa),
136    )
137}
138/// Build a mapConst application expression.
139pub fn make_map_const_expr(f_ty: Expr, a: Expr, fb: Expr) -> Expr {
140    Expr::App(
141        Box::new(Expr::App(
142            Box::new(Expr::App(
143                Box::new(Expr::Const(Name::str("Functor.mapConst"), vec![])),
144                Box::new(f_ty),
145            )),
146            Box::new(a),
147        )),
148        Box::new(fb),
149    )
150}
151/// Check the identity law for Option.
152pub fn option_identity_law<A: Clone + PartialEq>(x: Option<A>) -> bool {
153    fmap_option(x.clone(), |a| a) == x
154}
155/// Check the composition law for Option.
156pub fn option_composition_law<A: Clone, B: Clone + PartialEq, C: PartialEq>(
157    x: Option<A>,
158    f: impl Fn(A) -> B + Clone,
159    g: impl Fn(B) -> C + Clone,
160) -> bool {
161    let f2 = f.clone();
162    let g2 = g.clone();
163    fmap_option(x.clone(), move |a| g(f(a))) == fmap_option(fmap_option(x, f2), g2)
164}
165/// Check the identity law for Vec.
166pub fn vec_identity_law<A: Clone + PartialEq>(xs: Vec<A>) -> bool {
167    fmap_vec(xs.clone(), |a| a) == xs
168}
169/// Map f over Option<Vec<A>>.
170pub fn fmap_option_vec<A, B, F: Fn(A) -> B>(opt_vec: Option<Vec<A>>, f: F) -> Option<Vec<B>> {
171    fmap_option(opt_vec, |v| fmap_vec(v, &f))
172}
173/// Map f over Vec<Option<A>>.
174pub fn fmap_vec_option<A, B, F: Fn(A) -> B>(v: Vec<Option<A>>, f: F) -> Vec<Option<B>> {
175    fmap_vec(v, |opt| fmap_option(opt, &f))
176}
177/// Map f over Vec<Result<A, E>>.
178pub fn fmap_vec_result<A, B, E, F: Fn(A) -> B>(v: Vec<Result<A, E>>, f: F) -> Vec<Result<B, E>> {
179    fmap_vec(v, |r| fmap_result(r, &f))
180}
181/// Option to Vec.
182pub fn option_to_vec<A>(opt: Option<A>) -> Vec<A> {
183    match opt {
184        Some(a) => vec![a],
185        None => vec![],
186    }
187}
188/// Vec to Option (first element).
189pub fn vec_to_option<A>(v: Vec<A>) -> Option<A> {
190    v.into_iter().next()
191}
192/// Flatten Option<Option<A>>.
193pub fn join_option<A>(opt: Option<Option<A>>) -> Option<A> {
194    opt.flatten()
195}
196/// Flatten Vec<Vec<A>>.
197pub fn join_vec<A>(vv: Vec<Vec<A>>) -> Vec<A> {
198    vv.into_iter().flatten().collect()
199}
200/// Apply Option<fn> to Option<A>.
201pub fn ap_option<A, B, F: Fn(A) -> B>(f: Option<F>, a: Option<A>) -> Option<B> {
202    match (f, a) {
203        (Some(g), Some(x)) => Some(g(x)),
204        _ => None,
205    }
206}
207/// Apply Vec<fn> to Vec<A> (cartesian product).
208#[allow(clippy::redundant_closure)]
209pub fn ap_vec<A: Clone, B, F: Fn(A) -> B>(fs: Vec<F>, xs: Vec<A>) -> Vec<B> {
210    fs.into_iter()
211        .flat_map(|f| xs.iter().cloned().map(move |x| f(x)))
212        .collect()
213}
214/// Monadic bind for Option.
215pub fn bind_option<A, B, F: Fn(A) -> Option<B>>(opt: Option<A>, f: F) -> Option<B> {
216    opt.and_then(f)
217}
218/// Monadic bind for Vec (list monad).
219pub fn bind_vec<A, B, F: Fn(A) -> Vec<B>>(v: Vec<A>, f: F) -> Vec<B> {
220    v.into_iter().flat_map(f).collect()
221}
222/// Traverse Vec<A> with Option effect.
223pub fn traverse_vec_option<A, B, F: Fn(A) -> Option<B>>(v: Vec<A>, f: F) -> Option<Vec<B>> {
224    v.into_iter().map(f).collect()
225}
226/// Traverse Vec<A> with Result effect.
227pub fn traverse_vec_result<A, B, E, F: Fn(A) -> Result<B, E>>(
228    v: Vec<A>,
229    f: F,
230) -> Result<Vec<B>, E> {
231    v.into_iter().map(f).collect()
232}
233/// Fold Vec from left.
234pub fn fold_left_vec<A, B, F: Fn(B, &A) -> B>(v: &[A], init: B, f: F) -> B {
235    v.iter().fold(init, f)
236}
237/// Fold Vec from right.
238pub fn fold_right_vec<A, B, F: Fn(&A, B) -> B>(v: &[A], init: B, f: F) -> B {
239    v.iter().rfold(init, |b, a| f(a, b))
240}
241/// Count elements.
242pub fn count_elements<A>(v: &[A]) -> usize {
243    v.len()
244}
245/// Sum u64 elements.
246pub fn sum_u64_slice(v: &[u64]) -> u64 {
247    v.iter().sum()
248}
249/// Lift a binary function into Option applicative.
250pub fn option_lift2<A, B, C, F: FnOnce(A, B) -> C>(f: F, a: Option<A>, b: Option<B>) -> Option<C> {
251    match (a, b) {
252        (Some(x), Some(y)) => Some(f(x, y)),
253        _ => None,
254    }
255}
256/// Lift a ternary function into Option applicative.
257pub fn option_lift3<A, B, C, D, F: FnOnce(A, B, C) -> D>(
258    f: F,
259    a: Option<A>,
260    b: Option<B>,
261    c: Option<C>,
262) -> Option<D> {
263    match (a, b, c) {
264        (Some(x), Some(y), Some(z)) => Some(f(x, y, z)),
265        _ => None,
266    }
267}
268/// Collect Some values from a slice.
269pub fn collect_somes<A: Clone>(opts: &[Option<A>]) -> Vec<A> {
270    opts.iter().filter_map(|o| o.clone()).collect()
271}
272/// Count Some values.
273pub fn count_somes<A>(opts: &[Option<A>]) -> usize {
274    opts.iter().filter(|o| o.is_some()).count()
275}
276/// Zip two Vecs into pairs.
277pub fn zip_vecs<A: Clone, B: Clone>(a: &[A], b: &[B]) -> Vec<(A, B)> {
278    a.iter()
279        .zip(b.iter())
280        .map(|(x, y)| (x.clone(), y.clone()))
281        .collect()
282}
283/// Unzip a Vec of pairs.
284pub fn unzip_pairs<A, B>(pairs: Vec<(A, B)>) -> (Vec<A>, Vec<B>) {
285    pairs.into_iter().unzip()
286}
287/// Find first element satisfying predicate.
288pub fn find_first<A, P: Fn(&A) -> bool>(v: &[A], pred: P) -> Option<&A> {
289    v.iter().find(|a| pred(a))
290}
291/// Partition by predicate.
292pub fn partition_by<A, P: Fn(&A) -> bool>(v: Vec<A>, pred: P) -> (Vec<A>, Vec<A>) {
293    v.into_iter().partition(|a| pred(a))
294}
295/// Scan left (prefix sums generalized).
296pub fn scan_left<A: Clone, B: Clone, F: Fn(B, &A) -> B>(v: &[A], init: B, f: F) -> Vec<B> {
297    let mut acc = init;
298    let mut result = vec![acc.clone()];
299    for a in v {
300        acc = f(acc, a);
301        result.push(acc.clone());
302    }
303    result
304}
305/// Group consecutive equal elements.
306pub fn group_by_eq<A: PartialEq + Clone>(v: Vec<A>) -> Vec<Vec<A>> {
307    let mut result: Vec<Vec<A>> = Vec::new();
308    for item in v {
309        if let Some(last) = result.last_mut() {
310            if last.first() == Some(&item) {
311                last.push(item);
312                continue;
313            }
314        }
315        result.push(vec![item]);
316    }
317    result
318}
319/// Interleave two Vecs.
320pub fn interleave<A>(a: Vec<A>, b: Vec<A>) -> Vec<A> {
321    let mut result = Vec::new();
322    let mut ai = a.into_iter();
323    let mut bi = b.into_iter();
324    loop {
325        match (ai.next(), bi.next()) {
326            (Some(x), Some(y)) => {
327                result.push(x);
328                result.push(y);
329            }
330            (Some(x), None) => {
331                result.push(x);
332                result.extend(ai);
333                break;
334            }
335            (None, Some(y)) => {
336                result.push(y);
337                result.extend(bi);
338                break;
339            }
340            (None, None) => break,
341        }
342    }
343    result
344}
345/// Rotate a Vec left by n positions.
346pub fn rotate_left<A: Clone>(v: Vec<A>, n: usize) -> Vec<A> {
347    if v.is_empty() {
348        return v;
349    }
350    let n = n % v.len();
351    let mut result = v[n..].to_vec();
352    result.extend_from_slice(&v[..n]);
353    result
354}
355/// Rotate a Vec right by n positions.
356pub fn rotate_right<A: Clone>(v: Vec<A>, n: usize) -> Vec<A> {
357    if v.is_empty() {
358        return v;
359    }
360    let len = v.len();
361    let n = n % len;
362    rotate_left(v, len.wrapping_sub(n) % len)
363}
364/// Deduplicate a Vec (keeps first occurrence).
365pub fn dedup_stable<A: PartialEq + Clone>(v: Vec<A>) -> Vec<A> {
366    let mut result = Vec::new();
367    for item in v {
368        if !result.contains(&item) {
369            result.push(item);
370        }
371    }
372    result
373}
374#[cfg(test)]
375mod tests {
376    use super::*;
377    #[test]
378    fn test_build_functor_env() {
379        let mut env = Environment::new();
380        assert!(build_functor_env(&mut env).is_ok());
381        assert!(env.get(&Name::str("Functor")).is_some());
382        assert!(env.get(&Name::str("Functor.map")).is_some());
383    }
384    #[test]
385    fn test_build_all_functor_decls() {
386        let mut env = Environment::new();
387        assert!(build_all_functor_decls(&mut env).is_ok());
388        assert!(env.contains(&Name::str("Functor")));
389        assert!(env.contains(&Name::str("Functor.map")));
390        assert!(env.contains(&Name::str("Functor.mapConst")));
391    }
392    #[test]
393    fn test_fmap_option_some() {
394        assert_eq!(fmap_option(Some(3), |x| x * 2), Some(6));
395    }
396    #[test]
397    fn test_fmap_option_none() {
398        assert_eq!(fmap_option(None::<i32>, |x| x * 2), None);
399    }
400    #[test]
401    fn test_fmap_vec() {
402        assert_eq!(fmap_vec(vec![1i32, 2, 3], |x| x + 10), vec![11, 12, 13]);
403    }
404    #[test]
405    fn test_fmap_result_ok() {
406        assert_eq!(fmap_result(Ok::<i32, &str>(5), |x| x + 1), Ok(6));
407    }
408    #[test]
409    fn test_fmap_result_err() {
410        assert!(fmap_result(Err::<i32, &str>("bad"), |x| x + 1).is_err());
411    }
412    #[test]
413    fn test_option_identity_law() {
414        assert!(option_identity_law(Some(42)));
415        assert!(option_identity_law::<i32>(None));
416    }
417    #[test]
418    fn test_option_composition_law() {
419        assert!(option_composition_law(Some(3i32), |a| a + 1, |b| b * 2));
420    }
421    #[test]
422    fn test_vec_identity_law() {
423        assert!(vec_identity_law(vec![1i32, 2, 3]));
424        assert!(vec_identity_law::<i32>(vec![]));
425    }
426    #[test]
427    fn test_either_left_right() {
428        let l: Either<i32, &str> = Either::Left(1);
429        let r: Either<i32, &str> = Either::Right("hi");
430        assert!(l.is_left());
431        assert!(r.is_right());
432    }
433    #[test]
434    fn test_either_bimap() {
435        let e: Either<i32, &str> = Either::Left(2);
436        let m = e.bimap(|x| x + 1, |s: &str| s.len());
437        assert_eq!(m.unwrap_left(), 3);
438    }
439    #[test]
440    fn test_pred_contramap() {
441        let is_pos = Pred::new(|x: i32| x > 0);
442        let is_len_pos = is_pos.contramap(|s: &str| s.len() as i32);
443        assert!(is_len_pos.test("hello"));
444        assert!(!is_len_pos.test(""));
445    }
446    #[test]
447    fn test_fmap_option_vec() {
448        let v: Option<Vec<i32>> = Some(vec![1, 2, 3]);
449        assert_eq!(fmap_option_vec(v, |x| x * 2), Some(vec![2, 4, 6]));
450    }
451    #[test]
452    fn test_natural_transformations() {
453        assert_eq!(option_to_vec(Some(1)), vec![1]);
454        assert_eq!(option_to_vec::<i32>(None), vec![]);
455        assert_eq!(vec_to_option(vec![1, 2, 3]), Some(1));
456    }
457    #[test]
458    fn test_join_option() {
459        assert_eq!(join_option(Some(Some(42))), Some(42));
460        assert_eq!(join_option::<i32>(None), None);
461    }
462    #[test]
463    fn test_join_vec() {
464        assert_eq!(join_vec(vec![vec![1, 2], vec![3]]), vec![1, 2, 3]);
465    }
466    #[test]
467    fn test_ap_option() {
468        let f: Option<fn(i32) -> i32> = Some(|x| x + 1);
469        assert_eq!(ap_option(f, Some(5)), Some(6));
470    }
471    #[test]
472    fn test_bind_option() {
473        assert_eq!(
474            bind_option(Some(5), |x| if x > 3 { Some(x * 2) } else { None }),
475            Some(10)
476        );
477    }
478    #[test]
479    fn test_bind_vec() {
480        assert_eq!(
481            bind_vec(vec![1i32, 2], |x| vec![x, x * 10]),
482            vec![1, 10, 2, 20]
483        );
484    }
485    #[test]
486    fn test_traverse_vec_option() {
487        assert_eq!(
488            traverse_vec_option(vec![1i32, 2, 3], |x| if x > 0 { Some(x * 2) } else { None }),
489            Some(vec![2, 4, 6])
490        );
491        assert_eq!(
492            traverse_vec_option(vec![1i32, -1], |x| if x > 0 { Some(x) } else { None }),
493            None
494        );
495    }
496    #[test]
497    fn test_traverse_vec_result() {
498        let r: Result<Vec<i32>, _> = traverse_vec_result(vec!["1", "2"], |s| s.parse::<i32>());
499        assert_eq!(r, Ok(vec![1, 2]));
500    }
501    #[test]
502    fn test_fold_left_vec() {
503        assert_eq!(fold_left_vec(&[1u64, 2, 3], 0, |acc, x| acc + x), 6);
504    }
505    #[test]
506    fn test_option_lift2() {
507        assert_eq!(option_lift2(|a, b| a + b, Some(3i32), Some(4)), Some(7));
508        assert_eq!(option_lift2(|a: i32, b: i32| a + b, None, Some(4)), None);
509    }
510    #[test]
511    fn test_option_lift3() {
512        assert_eq!(
513            option_lift3(|a, b, c| a + b + c, Some(1i32), Some(2), Some(3)),
514            Some(6)
515        );
516    }
517    #[test]
518    fn test_collect_somes() {
519        let opts = vec![Some(1), None, Some(3), None];
520        assert_eq!(collect_somes(&opts), vec![1, 3]);
521    }
522    #[test]
523    fn test_zip_unzip() {
524        let pairs = zip_vecs(&[1i32, 2], &["a", "b"]);
525        assert_eq!(pairs, vec![(1, "a"), (2, "b")]);
526        let (a, b): (Vec<i32>, Vec<&str>) = unzip_pairs(pairs);
527        assert_eq!(a, vec![1, 2]);
528        assert_eq!(b, vec!["a", "b"]);
529    }
530    #[test]
531    fn test_find_first() {
532        let v = vec![1, 2, 3, 4, 5];
533        assert_eq!(find_first(&v, |x| *x > 3), Some(&4));
534    }
535    #[test]
536    fn test_partition_by() {
537        let v = vec![1i32, 2, 3, 4, 5];
538        let (evens, odds) = partition_by(v, |x| x % 2 == 0);
539        assert_eq!(evens, vec![2, 4]);
540        assert_eq!(odds, vec![1, 3, 5]);
541    }
542    #[test]
543    fn test_scan_left() {
544        let v = vec![1u64, 2, 3, 4];
545        let scanned = scan_left(&v, 0u64, |acc, x| acc + x);
546        assert_eq!(scanned, vec![0, 1, 3, 6, 10]);
547    }
548    #[test]
549    fn test_rotate_left() {
550        assert_eq!(rotate_left(vec![1, 2, 3, 4, 5], 2), vec![3, 4, 5, 1, 2]);
551    }
552    #[test]
553    fn test_dedup_stable() {
554        assert_eq!(dedup_stable(vec![1, 2, 1, 3, 2]), vec![1, 2, 3]);
555    }
556    #[test]
557    fn test_interleave() {
558        assert_eq!(
559            interleave(vec![1, 3, 5], vec![2, 4, 6]),
560            vec![1, 2, 3, 4, 5, 6]
561        );
562    }
563    #[test]
564    fn test_make_fmap_expr() {
565        let result = make_fmap_expr(
566            Expr::Sort(Level::zero()),
567            Expr::Sort(Level::zero()),
568            Expr::Sort(Level::zero()),
569        );
570        assert!(matches!(result, Expr::App(_, _)));
571    }
572    #[test]
573    fn test_option_functor_wrapper() {
574        let of = OptionFunctor(Some(5i32));
575        let mapped = of.fmap(|x| x.to_string());
576        assert_eq!(mapped.0, Some("5".to_string()));
577    }
578    #[test]
579    fn test_vec_functor_wrapper() {
580        let vf = VecFunctor(vec![1i32, 2, 3]);
581        let mapped = vf.fmap(|x| x * x);
582        assert_eq!(mapped.0, vec![1, 4, 9]);
583    }
584    #[test]
585    fn test_result_functor_wrapper() {
586        let rf: ResultFunctor<i32, &str> = ResultFunctor(Ok(7));
587        let mapped = rf.fmap(|x| x + 1);
588        assert_eq!(mapped.0, Ok(8));
589    }
590}
591/// Apply a function to a value, returning the value unchanged (tap/inspect).
592pub fn tap<A, F: FnMut(&A)>(v: A, mut f: F) -> A {
593    f(&v);
594    v
595}
596/// Apply a function to a value in Option, returning the value unchanged.
597pub fn tap_option<A, F: Fn(&A)>(opt: Option<A>, f: F) -> Option<A> {
598    if let Some(ref v) = opt {
599        f(v);
600    }
601    opt
602}
603/// Apply a function to each element of a Vec, returning the Vec unchanged.
604pub fn tap_vec<A, F: Fn(&A)>(v: Vec<A>, f: F) -> Vec<A> {
605    for x in &v {
606        f(x);
607    }
608    v
609}
610/// Repeatedly apply f to x until predicate p returns false.
611pub fn iterate_while<A: Clone, F: Fn(A) -> A, P: Fn(&A) -> bool>(mut x: A, f: F, p: P) -> A {
612    while p(&x) {
613        x = f(x);
614    }
615    x
616}
617/// Generate a Vec by iterating f from seed n times.
618pub fn generate_vec<A: Clone, F: Fn(A) -> A>(seed: A, f: F, n: usize) -> Vec<A> {
619    let mut result = vec![seed.clone()];
620    let mut cur = seed;
621    for _ in 0..n {
622        cur = f(cur);
623        result.push(cur.clone());
624    }
625    result
626}
627/// Apply a function n times.
628pub fn iterate_n<A, F: Fn(A) -> A>(mut x: A, f: F, n: usize) -> A {
629    for _ in 0..n {
630        x = f(x);
631    }
632    x
633}
634/// Memoize a function using a Vec cache (for usize -> A).
635pub fn memoize_vec<A: Clone, F: Fn(usize) -> A>(f: F, n: usize) -> Vec<A> {
636    (0..n).map(f).collect()
637}
638/// Compose two functions.
639pub fn compose<A, B, C, F: Fn(A) -> B, G: Fn(B) -> C>(f: F, g: G) -> impl Fn(A) -> C {
640    move |a| g(f(a))
641}
642/// Compose three functions.
643pub fn compose3<A, B, C, D, F: Fn(A) -> B, G: Fn(B) -> C, H: Fn(C) -> D>(
644    f: F,
645    g: G,
646    h: H,
647) -> impl Fn(A) -> D {
648    move |a| h(g(f(a)))
649}
650/// Identity function.
651pub fn identity<A>(a: A) -> A {
652    a
653}
654/// Constant function.
655pub fn constant<A: Clone, B>(a: A) -> impl Fn(B) -> A {
656    move |_| a.clone()
657}
658/// Flip the arguments of a binary function.
659pub fn flip2<A, B, C, F: Fn(A, B) -> C>(f: F) -> impl Fn(B, A) -> C {
660    move |b, a| f(a, b)
661}
662/// Apply f to a if cond is true, otherwise return a.
663pub fn apply_if<A, F: Fn(A) -> A>(cond: bool, a: A, f: F) -> A {
664    if cond {
665        f(a)
666    } else {
667        a
668    }
669}
670/// Apply f to elements satisfying pred, keeping others unchanged.
671pub fn map_where<A, F: Fn(A) -> A, P: Fn(&A) -> bool>(v: Vec<A>, pred: P, f: F) -> Vec<A> {
672    v.into_iter()
673        .map(|x| if pred(&x) { f(x) } else { x })
674        .collect()
675}
676/// Split a Vec at the first element satisfying pred.
677pub fn split_at_pred<A, P: Fn(&A) -> bool>(v: Vec<A>, pred: P) -> (Vec<A>, Vec<A>) {
678    let pos = v.iter().position(pred).unwrap_or(v.len());
679    let mut right = v;
680    let left = right.drain(..pos).collect();
681    (left, right)
682}
683/// Flatten an Option<Vec<A>> to Vec<A>.
684pub fn flatten_opt_vec<A>(opt: Option<Vec<A>>) -> Vec<A> {
685    opt.unwrap_or_default()
686}
687/// Flatten a Vec<Option<A>> to Vec<A> (keep Some values).
688pub fn flatten_vec_opt<A>(v: Vec<Option<A>>) -> Vec<A> {
689    v.into_iter().flatten().collect()
690}
691/// Chunk a Vec into sub-Vecs of size n.
692pub fn chunk<A: Clone>(v: Vec<A>, n: usize) -> Vec<Vec<A>> {
693    if n == 0 {
694        return vec![];
695    }
696    v.chunks(n).map(|c| c.to_vec()).collect()
697}
698/// Sliding window of size n.
699pub fn windows<A: Clone>(v: &[A], n: usize) -> Vec<Vec<A>> {
700    v.windows(n).map(|w| w.to_vec()).collect()
701}
702/// Transpose a Vec<Vec<A>> (assuming all inner vecs have the same length).
703pub fn transpose<A: Clone>(vv: Vec<Vec<A>>) -> Vec<Vec<A>> {
704    if vv.is_empty() {
705        return vec![];
706    }
707    let n = vv[0].len();
708    (0..n)
709        .map(|i| vv.iter().filter_map(|row| row.get(i)).cloned().collect())
710        .collect()
711}
712/// Map with index.
713pub fn map_indexed<A, B, F: Fn(usize, A) -> B>(v: Vec<A>, f: F) -> Vec<B> {
714    v.into_iter().enumerate().map(|(i, a)| f(i, a)).collect()
715}
716/// Flat map with index.
717pub fn flat_map_indexed<A, B, F: Fn(usize, A) -> Vec<B>>(v: Vec<A>, f: F) -> Vec<B> {
718    v.into_iter()
719        .enumerate()
720        .flat_map(|(i, a)| f(i, a))
721        .collect()
722}
723/// Filter with index.
724pub fn filter_indexed<A, P: Fn(usize, &A) -> bool>(v: Vec<A>, pred: P) -> Vec<A> {
725    v.into_iter()
726        .enumerate()
727        .filter(|(i, a)| pred(*i, a))
728        .map(|(_, a)| a)
729        .collect()
730}
731/// Repeat a value n times into a Vec.
732pub fn replicate<A: Clone>(n: usize, a: A) -> Vec<A> {
733    vec![a; n]
734}
735/// Take while predicate holds.
736pub fn take_while<A, P: Fn(&A) -> bool>(v: Vec<A>, pred: P) -> Vec<A> {
737    v.into_iter().take_while(|a| pred(a)).collect()
738}
739/// Drop while predicate holds.
740pub fn drop_while<A, P: Fn(&A) -> bool>(v: Vec<A>, pred: P) -> Vec<A> {
741    v.into_iter().skip_while(|a| pred(a)).collect()
742}
743/// Span: split into (take_while, drop_while).
744pub fn span<A, P: Fn(&A) -> bool>(v: Vec<A>, pred: P) -> (Vec<A>, Vec<A>) {
745    let pos = v.iter().position(|a| !pred(a)).unwrap_or(v.len());
746    let mut right = v;
747    let left = right.drain(..pos).collect();
748    (left, right)
749}
750#[cfg(test)]
751mod extra_tests {
752    use super::*;
753    #[test]
754    fn test_tap() {
755        let mut side = 0;
756        let v = tap(42, |x| {
757            let _ = x;
758            side = 1;
759        });
760        assert_eq!(v, 42);
761        assert_eq!(side, 1);
762    }
763    #[test]
764    fn test_iterate_while() {
765        let result = iterate_while(1u32, |x| x * 2, |x| *x < 100);
766        assert!(result >= 100);
767    }
768    #[test]
769    fn test_generate_vec() {
770        let v = generate_vec(1u64, |x| x * 2, 4);
771        assert_eq!(v, vec![1, 2, 4, 8, 16]);
772    }
773    #[test]
774    fn test_iterate_n() {
775        let result = iterate_n(1u64, |x| x * 2, 10);
776        assert_eq!(result, 1024);
777    }
778    #[test]
779    fn test_compose() {
780        let f = compose(|x: i32| x + 1, |x: i32| x * 2);
781        assert_eq!(f(3), 8);
782    }
783    #[test]
784    fn test_compose3() {
785        let f = compose3(|x: i32| x + 1, |x: i32| x * 2, |x: i32| x - 1);
786        assert_eq!(f(3), 7);
787    }
788    #[test]
789    fn test_identity() {
790        assert_eq!(identity(42), 42);
791        assert_eq!(identity("hello"), "hello");
792    }
793    #[test]
794    fn test_constant() {
795        let always5 = constant(5i32);
796        assert_eq!(always5("anything"), 5);
797        assert_eq!(always5("any"), 5);
798    }
799    #[test]
800    fn test_flip2() {
801        let sub = |a: i32, b: i32| a - b;
802        let flipped = flip2(sub);
803        assert_eq!(flipped(1, 10), 9);
804    }
805    #[test]
806    fn test_apply_if_true() {
807        let result = apply_if(true, 5, |x| x * 2);
808        assert_eq!(result, 10);
809    }
810    #[test]
811    fn test_apply_if_false() {
812        let result = apply_if(false, 5, |x| x * 2);
813        assert_eq!(result, 5);
814    }
815    #[test]
816    fn test_map_where() {
817        let v = vec![1i32, 2, 3, 4, 5];
818        let result = map_where(v, |x| *x % 2 == 0, |x| x * 10);
819        assert_eq!(result, vec![1, 20, 3, 40, 5]);
820    }
821    #[test]
822    fn test_flatten_opt_vec() {
823        assert_eq!(flatten_opt_vec(Some(vec![1, 2, 3])), vec![1, 2, 3]);
824        assert_eq!(flatten_opt_vec::<i32>(None), vec![]);
825    }
826    #[test]
827    fn test_flatten_vec_opt() {
828        let v = vec![Some(1), None, Some(3)];
829        assert_eq!(flatten_vec_opt(v), vec![1, 3]);
830    }
831    #[test]
832    fn test_chunk() {
833        let v = vec![1, 2, 3, 4, 5];
834        assert_eq!(chunk(v, 2), vec![vec![1, 2], vec![3, 4], vec![5]]);
835    }
836    #[test]
837    fn test_windows() {
838        let v = vec![1, 2, 3, 4];
839        assert_eq!(windows(&v, 2), vec![vec![1, 2], vec![2, 3], vec![3, 4]]);
840    }
841    #[test]
842    fn test_transpose() {
843        let vv = vec![vec![1, 2, 3], vec![4, 5, 6]];
844        let t = transpose(vv);
845        assert_eq!(t, vec![vec![1, 4], vec![2, 5], vec![3, 6]]);
846    }
847    #[test]
848    fn test_map_indexed() {
849        let v = vec!["a", "b", "c"];
850        let result = map_indexed(v, |i, s| format!("{}{}", i, s));
851        assert_eq!(result, vec!["0a", "1b", "2c"]);
852    }
853    #[test]
854    fn test_replicate() {
855        assert_eq!(replicate(4, 0i32), vec![0, 0, 0, 0]);
856    }
857    #[test]
858    fn test_take_while() {
859        let v = vec![1, 2, 3, 4, 5];
860        assert_eq!(take_while(v, |x| *x < 4), vec![1, 2, 3]);
861    }
862    #[test]
863    fn test_drop_while() {
864        let v = vec![1, 2, 3, 4, 5];
865        assert_eq!(drop_while(v, |x| *x < 4), vec![4, 5]);
866    }
867    #[test]
868    fn test_span() {
869        let v = vec![1, 2, 3, 4, 5];
870        let (left, right) = span(v, |x| *x < 4);
871        assert_eq!(left, vec![1, 2, 3]);
872        assert_eq!(right, vec![4, 5]);
873    }
874    #[test]
875    fn test_memoize_vec() {
876        let cached = memoize_vec(|i| i * i, 5);
877        assert_eq!(cached, vec![0, 1, 4, 9, 16]);
878    }
879}
880/// A trait that models the `Foldable` typeclass.
881///
882/// A foldable structure can be reduced to a single value by combining
883/// all elements with a binary operation and an initial accumulator.
884pub trait Foldable<A> {
885    /// Fold from the left.
886    fn fold_left<B>(self, init: B, f: impl Fn(B, A) -> B) -> B;
887    /// Fold from the right.
888    fn fold_right<B>(self, init: B, f: impl Fn(A, B) -> B) -> B;
889    /// Compute the length of the structure.
890    fn length(self) -> usize
891    where
892        Self: Sized,
893        A: Clone,
894    {
895        self.fold_left(0, |acc, _| acc + 1)
896    }
897    /// Check whether any element satisfies the predicate.
898    fn any<F: Fn(&A) -> bool>(self, pred: F) -> bool
899    where
900        Self: Sized,
901        A: Clone,
902    {
903        self.fold_left(false, |acc, x| acc || pred(&x))
904    }
905    /// Check whether all elements satisfy the predicate.
906    fn all<F: Fn(&A) -> bool>(self, pred: F) -> bool
907    where
908        Self: Sized,
909        A: Clone,
910    {
911        self.fold_left(true, |acc, x| acc && pred(&x))
912    }
913}
914impl<A: Clone> Foldable<A> for Vec<A> {
915    fn fold_left<B>(self, init: B, f: impl Fn(B, A) -> B) -> B {
916        self.into_iter().fold(init, f)
917    }
918    fn fold_right<B>(self, init: B, f: impl Fn(A, B) -> B) -> B {
919        self.into_iter().rev().fold(init, |acc, x| f(x, acc))
920    }
921}
922/// A trait that models the `Traversable` typeclass.
923///
924/// A traversable structure can be mapped with an effectful function
925/// and the effects can be combined.
926pub trait Traversable<A, B, E> {
927    /// The output container type.
928    type Output;
929    /// Traverse the structure, applying `f` to each element.
930    fn traverse(self, f: impl Fn(A) -> Result<B, E>) -> Result<Self::Output, E>;
931}
932impl<A, B, E> Traversable<A, B, E> for Vec<A> {
933    type Output = Vec<B>;
934    fn traverse(self, f: impl Fn(A) -> Result<B, E>) -> Result<Vec<B>, E> {
935        let mut result = Vec::with_capacity(self.len());
936        for item in self {
937            result.push(f(item)?);
938        }
939        Ok(result)
940    }
941}
942#[cfg(test)]
943mod extra_functor_tests {
944    use super::*;
945    #[test]
946    fn test_foldable_fold_left() {
947        let v = vec![1i32, 2, 3, 4, 5];
948        let sum = v.fold_left(0i32, |acc, x| acc + x);
949        assert_eq!(sum, 15);
950    }
951    #[test]
952    fn test_foldable_fold_right() {
953        let v = vec![1i32, 2, 3];
954        let result = v.fold_right(Vec::<i32>::new(), |x, mut acc| {
955            acc.insert(0, x);
956            acc
957        });
958        assert_eq!(result, vec![1, 2, 3]);
959    }
960    #[test]
961    fn test_foldable_any_true() {
962        let v = vec![1i32, 2, 3];
963        assert!(v.any(|x| *x == 2));
964    }
965    #[test]
966    fn test_foldable_any_false() {
967        let v = vec![1i32, 2, 3];
968        assert!(!v.any(|x| *x == 99));
969    }
970    #[test]
971    fn test_foldable_all_true() {
972        let v = vec![2i32, 4, 6];
973        assert!(v.all(|x| *x % 2 == 0));
974    }
975    #[test]
976    fn test_foldable_all_false() {
977        let v = vec![2i32, 3, 6];
978        assert!(!v.all(|x| *x % 2 == 0));
979    }
980    #[test]
981    fn test_traversable_ok() {
982        let v = vec![1i32, 2, 3];
983        let result: Result<Vec<i32>, &str> = v.traverse(|x| Ok(x * 2));
984        assert_eq!(result, Ok(vec![2, 4, 6]));
985    }
986    #[test]
987    fn test_traversable_err() {
988        let v = vec![1i32, 0, 3];
989        let result: Result<Vec<i32>, &str> =
990            v.traverse(|x| if x != 0 { Ok(x * 2) } else { Err("zero") });
991        assert_eq!(result, Err("zero"));
992    }
993    #[test]
994    fn test_reader_run() {
995        let r: Reader<i32, i32> = Reader::new(|env| env * 2);
996        assert_eq!(r.run_reader(5), 10);
997    }
998    #[test]
999    fn test_reader_map() {
1000        let r: Reader<i32, i32> = Reader::new(|env| env + 1);
1001        let r2 = r.map(|x| x * 3);
1002        assert_eq!(r2.run_reader(4), 15);
1003    }
1004    #[test]
1005    fn test_reader_pure() {
1006        let r: Reader<i32, i32> = Reader::pure(42);
1007        assert_eq!(r.run_reader(999), 42);
1008    }
1009    #[test]
1010    fn test_writer_run() {
1011        let w: Writer<i32, Vec<String>> = Writer::new(42, vec!["logged".to_string()]);
1012        let (v, log) = w.run();
1013        assert_eq!(v, 42);
1014        assert_eq!(log, vec!["logged".to_string()]);
1015    }
1016    #[test]
1017    fn test_writer_pure() {
1018        let w: Writer<i32, Vec<String>> = Writer::pure(7);
1019        assert_eq!(w.get_value(), 7);
1020    }
1021}
1022pub fn ftr_ext_identity_law_ty() -> Expr {
1023    let type1 = Expr::Sort(Level::succ(Level::zero()));
1024    Expr::Pi(
1025        BinderInfo::Default,
1026        Name::str("f_alpha"),
1027        Box::new(type1.clone()),
1028        Box::new(type1),
1029    )
1030}
1031pub fn ftr_ext_composition_law_ty() -> Expr {
1032    let type1 = Expr::Sort(Level::succ(Level::zero()));
1033    Expr::Pi(
1034        BinderInfo::Default,
1035        Name::str("f_alpha"),
1036        Box::new(type1.clone()),
1037        Box::new(type1),
1038    )
1039}
1040pub fn ftr_ext_naturality_ty() -> Expr {
1041    let type1 = Expr::Sort(Level::succ(Level::zero()));
1042    Expr::Pi(
1043        BinderInfo::Default,
1044        Name::str("nat_ty"),
1045        Box::new(type1.clone()),
1046        Box::new(type1),
1047    )
1048}
1049pub fn ftr_ext_list_identity_ty() -> Expr {
1050    let type1 = Expr::Sort(Level::succ(Level::zero()));
1051    Expr::Pi(
1052        BinderInfo::Default,
1053        Name::str("list_a"),
1054        Box::new(Expr::App(
1055            Box::new(Expr::Const(Name::str("List"), vec![])),
1056            Box::new(type1.clone()),
1057        )),
1058        Box::new(Expr::App(
1059            Box::new(Expr::Const(Name::str("List"), vec![])),
1060            Box::new(type1),
1061        )),
1062    )
1063}
1064pub fn ftr_ext_list_composition_ty() -> Expr {
1065    let type1 = Expr::Sort(Level::succ(Level::zero()));
1066    Expr::Pi(
1067        BinderInfo::Default,
1068        Name::str("list_compose"),
1069        Box::new(type1.clone()),
1070        Box::new(type1),
1071    )
1072}
1073pub fn ftr_ext_option_identity_ty() -> Expr {
1074    let type1 = Expr::Sort(Level::succ(Level::zero()));
1075    Expr::Pi(
1076        BinderInfo::Default,
1077        Name::str("opt_id"),
1078        Box::new(Expr::App(
1079            Box::new(Expr::Const(Name::str("Option"), vec![])),
1080            Box::new(type1.clone()),
1081        )),
1082        Box::new(Expr::App(
1083            Box::new(Expr::Const(Name::str("Option"), vec![])),
1084            Box::new(type1),
1085        )),
1086    )
1087}
1088pub fn ftr_ext_option_composition_ty() -> Expr {
1089    let type1 = Expr::Sort(Level::succ(Level::zero()));
1090    Expr::Pi(
1091        BinderInfo::Default,
1092        Name::str("opt_comp"),
1093        Box::new(type1.clone()),
1094        Box::new(type1),
1095    )
1096}
1097pub fn ftr_ext_result_identity_ty() -> Expr {
1098    let type1 = Expr::Sort(Level::succ(Level::zero()));
1099    Expr::Pi(
1100        BinderInfo::Default,
1101        Name::str("res_id"),
1102        Box::new(type1.clone()),
1103        Box::new(type1),
1104    )
1105}
1106pub fn ftr_ext_pair_fmap_ty() -> Expr {
1107    let type1 = Expr::Sort(Level::succ(Level::zero()));
1108    Expr::Pi(
1109        BinderInfo::Default,
1110        Name::str("pair_fmap"),
1111        Box::new(type1.clone()),
1112        Box::new(type1),
1113    )
1114}
1115pub fn ftr_ext_bifunctor_identity_ty() -> Expr {
1116    let type1 = Expr::Sort(Level::succ(Level::zero()));
1117    Expr::Pi(
1118        BinderInfo::Default,
1119        Name::str("bimap_id"),
1120        Box::new(type1.clone()),
1121        Box::new(type1),
1122    )
1123}
1124pub fn ftr_ext_bifunctor_composition_ty() -> Expr {
1125    let type1 = Expr::Sort(Level::succ(Level::zero()));
1126    Expr::Pi(
1127        BinderInfo::Default,
1128        Name::str("bimap_comp"),
1129        Box::new(type1.clone()),
1130        Box::new(type1),
1131    )
1132}
1133pub fn ftr_ext_contramap_identity_ty() -> Expr {
1134    let type1 = Expr::Sort(Level::succ(Level::zero()));
1135    Expr::Pi(
1136        BinderInfo::Default,
1137        Name::str("cmap_id"),
1138        Box::new(type1.clone()),
1139        Box::new(type1),
1140    )
1141}
1142pub fn ftr_ext_contramap_composition_ty() -> Expr {
1143    let type1 = Expr::Sort(Level::succ(Level::zero()));
1144    Expr::Pi(
1145        BinderInfo::Default,
1146        Name::str("cmap_comp"),
1147        Box::new(type1.clone()),
1148        Box::new(type1),
1149    )
1150}
1151pub fn ftr_ext_profunctor_identity_ty() -> Expr {
1152    let type1 = Expr::Sort(Level::succ(Level::zero()));
1153    Expr::Pi(
1154        BinderInfo::Default,
1155        Name::str("dimap_id"),
1156        Box::new(type1.clone()),
1157        Box::new(type1),
1158    )
1159}
1160pub fn ftr_ext_profunctor_composition_ty() -> Expr {
1161    let type1 = Expr::Sort(Level::succ(Level::zero()));
1162    Expr::Pi(
1163        BinderInfo::Default,
1164        Name::str("dimap_comp"),
1165        Box::new(type1.clone()),
1166        Box::new(type1),
1167    )
1168}
1169pub fn ftr_ext_ap_identity_ty() -> Expr {
1170    let type1 = Expr::Sort(Level::succ(Level::zero()));
1171    Expr::Pi(
1172        BinderInfo::Default,
1173        Name::str("ap_id"),
1174        Box::new(type1.clone()),
1175        Box::new(type1),
1176    )
1177}
1178pub fn ftr_ext_ap_homomorphism_ty() -> Expr {
1179    let type1 = Expr::Sort(Level::succ(Level::zero()));
1180    Expr::Pi(
1181        BinderInfo::Default,
1182        Name::str("ap_hom"),
1183        Box::new(type1.clone()),
1184        Box::new(type1),
1185    )
1186}
1187pub fn ftr_ext_ap_interchange_ty() -> Expr {
1188    let type1 = Expr::Sort(Level::succ(Level::zero()));
1189    Expr::Pi(
1190        BinderInfo::Default,
1191        Name::str("ap_interchange"),
1192        Box::new(type1.clone()),
1193        Box::new(type1),
1194    )
1195}
1196pub fn ftr_ext_ap_composition_ty() -> Expr {
1197    let type1 = Expr::Sort(Level::succ(Level::zero()));
1198    Expr::Pi(
1199        BinderInfo::Default,
1200        Name::str("ap_comp"),
1201        Box::new(type1.clone()),
1202        Box::new(type1),
1203    )
1204}
1205pub fn ftr_ext_monoidal_unit_ty() -> Expr {
1206    let type1 = Expr::Sort(Level::succ(Level::zero()));
1207    Expr::Pi(
1208        BinderInfo::Default,
1209        Name::str("mono_unit"),
1210        Box::new(type1.clone()),
1211        Box::new(type1),
1212    )
1213}
1214pub fn ftr_ext_monoidal_zip_ty() -> Expr {
1215    let type1 = Expr::Sort(Level::succ(Level::zero()));
1216    Expr::Pi(
1217        BinderInfo::Default,
1218        Name::str("mono_zip"),
1219        Box::new(type1.clone()),
1220        Box::new(type1),
1221    )
1222}
1223pub fn ftr_ext_strong_first_ty() -> Expr {
1224    let type1 = Expr::Sort(Level::succ(Level::zero()));
1225    Expr::Pi(
1226        BinderInfo::Default,
1227        Name::str("strong_first"),
1228        Box::new(type1.clone()),
1229        Box::new(type1),
1230    )
1231}
1232pub fn ftr_ext_strong_second_ty() -> Expr {
1233    let type1 = Expr::Sort(Level::succ(Level::zero()));
1234    Expr::Pi(
1235        BinderInfo::Default,
1236        Name::str("strong_second"),
1237        Box::new(type1.clone()),
1238        Box::new(type1),
1239    )
1240}
1241pub fn ftr_ext_cartesian_copy_ty() -> Expr {
1242    let type1 = Expr::Sort(Level::succ(Level::zero()));
1243    Expr::Pi(
1244        BinderInfo::Default,
1245        Name::str("cartesian_copy"),
1246        Box::new(type1.clone()),
1247        Box::new(type1),
1248    )
1249}
1250pub fn ftr_ext_cartesian_delete_ty() -> Expr {
1251    let type1 = Expr::Sort(Level::succ(Level::zero()));
1252    Expr::Pi(
1253        BinderInfo::Default,
1254        Name::str("cartesian_delete"),
1255        Box::new(type1.clone()),
1256        Box::new(type1),
1257    )
1258}
1259pub fn ftr_ext_closed_apply_ty() -> Expr {
1260    let type1 = Expr::Sort(Level::succ(Level::zero()));
1261    Expr::Pi(
1262        BinderInfo::Default,
1263        Name::str("closed_apply"),
1264        Box::new(type1.clone()),
1265        Box::new(type1),
1266    )
1267}
1268pub fn ftr_ext_closed_curry_ty() -> Expr {
1269    let type1 = Expr::Sort(Level::succ(Level::zero()));
1270    Expr::Pi(
1271        BinderInfo::Default,
1272        Name::str("closed_curry"),
1273        Box::new(type1.clone()),
1274        Box::new(type1),
1275    )
1276}
1277pub fn ftr_ext_traverse_identity_ty() -> Expr {
1278    let type1 = Expr::Sort(Level::succ(Level::zero()));
1279    Expr::Pi(
1280        BinderInfo::Default,
1281        Name::str("trav_id"),
1282        Box::new(type1.clone()),
1283        Box::new(type1),
1284    )
1285}
1286pub fn ftr_ext_traverse_composition_ty() -> Expr {
1287    let type1 = Expr::Sort(Level::succ(Level::zero()));
1288    Expr::Pi(
1289        BinderInfo::Default,
1290        Name::str("trav_comp"),
1291        Box::new(type1.clone()),
1292        Box::new(type1),
1293    )
1294}
1295pub fn ftr_ext_fold_consistent_ty() -> Expr {
1296    let type1 = Expr::Sort(Level::succ(Level::zero()));
1297    Expr::Pi(
1298        BinderInfo::Default,
1299        Name::str("fold_consist"),
1300        Box::new(type1.clone()),
1301        Box::new(type1),
1302    )
1303}
1304pub fn ftr_ext_foldmap_morphism_ty() -> Expr {
1305    let type1 = Expr::Sort(Level::succ(Level::zero()));
1306    Expr::Pi(
1307        BinderInfo::Default,
1308        Name::str("foldmap_morph"),
1309        Box::new(type1.clone()),
1310        Box::new(type1),
1311    )
1312}
1313pub fn ftr_ext_representable_tabulate_ty() -> Expr {
1314    let type1 = Expr::Sort(Level::succ(Level::zero()));
1315    Expr::Pi(
1316        BinderInfo::Default,
1317        Name::str("rep_tab"),
1318        Box::new(type1.clone()),
1319        Box::new(type1),
1320    )
1321}
1322pub fn ftr_ext_representable_index_ty() -> Expr {
1323    let type1 = Expr::Sort(Level::succ(Level::zero()));
1324    Expr::Pi(
1325        BinderInfo::Default,
1326        Name::str("rep_idx"),
1327        Box::new(type1.clone()),
1328        Box::new(type1),
1329    )
1330}
1331pub fn ftr_ext_kan_left_ty() -> Expr {
1332    let type1 = Expr::Sort(Level::succ(Level::zero()));
1333    let type2 = Expr::Sort(Level::succ(Level::succ(Level::zero())));
1334    Expr::Pi(
1335        BinderInfo::Default,
1336        Name::str("lan_k"),
1337        Box::new(type2),
1338        Box::new(type1),
1339    )
1340}
1341pub fn ftr_ext_kan_right_ty() -> Expr {
1342    let type1 = Expr::Sort(Level::succ(Level::zero()));
1343    let type2 = Expr::Sort(Level::succ(Level::succ(Level::zero())));
1344    Expr::Pi(
1345        BinderInfo::Default,
1346        Name::str("ran_k"),
1347        Box::new(type2),
1348        Box::new(type1),
1349    )
1350}
1351pub fn ftr_ext_day_conv_unit_ty() -> Expr {
1352    let type1 = Expr::Sort(Level::succ(Level::zero()));
1353    Expr::Pi(
1354        BinderInfo::Default,
1355        Name::str("day_unit"),
1356        Box::new(type1.clone()),
1357        Box::new(type1),
1358    )
1359}
1360pub fn ftr_ext_day_conv_assoc_ty() -> Expr {
1361    let type1 = Expr::Sort(Level::succ(Level::zero()));
1362    Expr::Pi(
1363        BinderInfo::Default,
1364        Name::str("day_assoc"),
1365        Box::new(type1.clone()),
1366        Box::new(type1),
1367    )
1368}
1369pub fn ftr_ext_compose_identity_ty() -> Expr {
1370    let type1 = Expr::Sort(Level::succ(Level::zero()));
1371    Expr::Pi(
1372        BinderInfo::Default,
1373        Name::str("fcomp_id"),
1374        Box::new(type1.clone()),
1375        Box::new(type1),
1376    )
1377}
1378pub fn ftr_ext_compose_assoc_ty() -> Expr {
1379    let type1 = Expr::Sort(Level::succ(Level::zero()));
1380    Expr::Pi(
1381        BinderInfo::Default,
1382        Name::str("fcomp_assoc"),
1383        Box::new(type1.clone()),
1384        Box::new(type1),
1385    )
1386}
1387pub fn ftr_ext_nat_trans_id_ty() -> Expr {
1388    let type1 = Expr::Sort(Level::succ(Level::zero()));
1389    Expr::Pi(
1390        BinderInfo::Default,
1391        Name::str("nat_trans_id"),
1392        Box::new(type1.clone()),
1393        Box::new(type1),
1394    )
1395}
1396pub fn ftr_ext_nat_trans_comp_ty() -> Expr {
1397    let type1 = Expr::Sort(Level::succ(Level::zero()));
1398    Expr::Pi(
1399        BinderInfo::Default,
1400        Name::str("nat_trans_comp"),
1401        Box::new(type1.clone()),
1402        Box::new(type1),
1403    )
1404}
1405pub fn ftr_ext_adjunction_unit_ty() -> Expr {
1406    let type1 = Expr::Sort(Level::succ(Level::zero()));
1407    Expr::Pi(
1408        BinderInfo::Default,
1409        Name::str("adj_unit"),
1410        Box::new(type1.clone()),
1411        Box::new(type1),
1412    )
1413}
1414pub fn ftr_ext_adjunction_counit_ty() -> Expr {
1415    let type1 = Expr::Sort(Level::succ(Level::zero()));
1416    Expr::Pi(
1417        BinderInfo::Default,
1418        Name::str("adj_counit"),
1419        Box::new(type1.clone()),
1420        Box::new(type1),
1421    )
1422}
1423pub fn ftr_ext_adjunction_triangle_ty() -> Expr {
1424    let type1 = Expr::Sort(Level::succ(Level::zero()));
1425    Expr::Pi(
1426        BinderInfo::Default,
1427        Name::str("adj_triangle"),
1428        Box::new(type1.clone()),
1429        Box::new(type1),
1430    )
1431}
1432pub fn ftr_ext_functor_cat_obj_ty() -> Expr {
1433    let type2 = Expr::Sort(Level::succ(Level::succ(Level::zero())));
1434    Expr::Pi(
1435        BinderInfo::Default,
1436        Name::str("fcat_obj"),
1437        Box::new(type2.clone()),
1438        Box::new(type2),
1439    )
1440}
1441pub fn ftr_ext_functor_cat_mor_ty() -> Expr {
1442    let type1 = Expr::Sort(Level::succ(Level::zero()));
1443    Expr::Pi(
1444        BinderInfo::Default,
1445        Name::str("fcat_mor"),
1446        Box::new(type1.clone()),
1447        Box::new(type1),
1448    )
1449}
1450pub fn ftr_ext_presheaf_ty() -> Expr {
1451    let type1 = Expr::Sort(Level::succ(Level::zero()));
1452    let type2 = Expr::Sort(Level::succ(Level::succ(Level::zero())));
1453    Expr::Pi(
1454        BinderInfo::Default,
1455        Name::str("presheaf"),
1456        Box::new(type2),
1457        Box::new(type1),
1458    )
1459}
1460pub fn ftr_ext_yoneda_lemma_ty() -> Expr {
1461    let type1 = Expr::Sort(Level::succ(Level::zero()));
1462    Expr::Pi(
1463        BinderInfo::Default,
1464        Name::str("yoneda"),
1465        Box::new(type1.clone()),
1466        Box::new(type1),
1467    )
1468}
1469pub fn ftr_ext_yoneda_embedding_ty() -> Expr {
1470    let type1 = Expr::Sort(Level::succ(Level::zero()));
1471    let type2 = Expr::Sort(Level::succ(Level::succ(Level::zero())));
1472    Expr::Pi(
1473        BinderInfo::Default,
1474        Name::str("yoneda_embed"),
1475        Box::new(type1),
1476        Box::new(type2),
1477    )
1478}
1479pub fn ftr_ext_sheaf_gluing_ty() -> Expr {
1480    let type1 = Expr::Sort(Level::succ(Level::zero()));
1481    Expr::Pi(
1482        BinderInfo::Default,
1483        Name::str("sheaf_glue"),
1484        Box::new(type1.clone()),
1485        Box::new(type1),
1486    )
1487}
1488pub fn ftr_ext_sheaf_locality_ty() -> Expr {
1489    let type1 = Expr::Sort(Level::succ(Level::zero()));
1490    Expr::Pi(
1491        BinderInfo::Default,
1492        Name::str("sheaf_local"),
1493        Box::new(type1.clone()),
1494        Box::new(type1),
1495    )
1496}
1497pub fn ftr_ext_fmap_preserves_eq_ty() -> Expr {
1498    let type1 = Expr::Sort(Level::succ(Level::zero()));
1499    Expr::Pi(
1500        BinderInfo::Default,
1501        Name::str("fmap_eq"),
1502        Box::new(type1.clone()),
1503        Box::new(type1),
1504    )
1505}
1506pub fn ftr_ext_free_functor_ty() -> Expr {
1507    let type1 = Expr::Sort(Level::succ(Level::zero()));
1508    Expr::Pi(
1509        BinderInfo::Default,
1510        Name::str("free_functor"),
1511        Box::new(type1.clone()),
1512        Box::new(type1),
1513    )
1514}
1515pub fn ftr_ext_cofree_functor_ty() -> Expr {
1516    let type1 = Expr::Sort(Level::succ(Level::zero()));
1517    Expr::Pi(
1518        BinderInfo::Default,
1519        Name::str("cofree_functor"),
1520        Box::new(type1.clone()),
1521        Box::new(type1),
1522    )
1523}
1524pub fn ftr_ext_exponential_functor_ty() -> Expr {
1525    let type1 = Expr::Sort(Level::succ(Level::zero()));
1526    Expr::Pi(
1527        BinderInfo::Default,
1528        Name::str("exp_functor"),
1529        Box::new(type1.clone()),
1530        Box::new(type1),
1531    )
1532}
1533/// Register all extended functor axioms in the environment.
1534pub fn register_functor_extended_axioms(env: &mut Environment) {
1535    let axioms: &[(&str, fn() -> Expr)] = &[
1536        ("Functor.Ext.IdentityLaw", ftr_ext_identity_law_ty),
1537        ("Functor.Ext.CompositionLaw", ftr_ext_composition_law_ty),
1538        ("Functor.Ext.Naturality", ftr_ext_naturality_ty),
1539        ("Functor.Ext.ListIdentity", ftr_ext_list_identity_ty),
1540        ("Functor.Ext.ListComposition", ftr_ext_list_composition_ty),
1541        ("Functor.Ext.OptionIdentity", ftr_ext_option_identity_ty),
1542        (
1543            "Functor.Ext.OptionComposition",
1544            ftr_ext_option_composition_ty,
1545        ),
1546        ("Functor.Ext.ResultIdentity", ftr_ext_result_identity_ty),
1547        ("Functor.Ext.PairFmap", ftr_ext_pair_fmap_ty),
1548        (
1549            "Functor.Ext.BifunctorIdentity",
1550            ftr_ext_bifunctor_identity_ty,
1551        ),
1552        (
1553            "Functor.Ext.BifunctorComposition",
1554            ftr_ext_bifunctor_composition_ty,
1555        ),
1556        (
1557            "Functor.Ext.ContramapIdentity",
1558            ftr_ext_contramap_identity_ty,
1559        ),
1560        (
1561            "Functor.Ext.ContramapComposition",
1562            ftr_ext_contramap_composition_ty,
1563        ),
1564        (
1565            "Functor.Ext.ProfunctorIdentity",
1566            ftr_ext_profunctor_identity_ty,
1567        ),
1568        (
1569            "Functor.Ext.ProfunctorComposition",
1570            ftr_ext_profunctor_composition_ty,
1571        ),
1572        ("Functor.Ext.ApIdentity", ftr_ext_ap_identity_ty),
1573        ("Functor.Ext.ApHomomorphism", ftr_ext_ap_homomorphism_ty),
1574        ("Functor.Ext.ApInterchange", ftr_ext_ap_interchange_ty),
1575        ("Functor.Ext.ApComposition", ftr_ext_ap_composition_ty),
1576        ("Functor.Ext.MonoidalUnit", ftr_ext_monoidal_unit_ty),
1577        ("Functor.Ext.MonoidalZip", ftr_ext_monoidal_zip_ty),
1578        ("Functor.Ext.StrongFirst", ftr_ext_strong_first_ty),
1579        ("Functor.Ext.StrongSecond", ftr_ext_strong_second_ty),
1580        ("Functor.Ext.CartesianCopy", ftr_ext_cartesian_copy_ty),
1581        ("Functor.Ext.CartesianDelete", ftr_ext_cartesian_delete_ty),
1582        ("Functor.Ext.ClosedApply", ftr_ext_closed_apply_ty),
1583        ("Functor.Ext.ClosedCurry", ftr_ext_closed_curry_ty),
1584        ("Functor.Ext.TraverseIdentity", ftr_ext_traverse_identity_ty),
1585        (
1586            "Functor.Ext.TraverseComposition",
1587            ftr_ext_traverse_composition_ty,
1588        ),
1589        ("Functor.Ext.FoldConsistent", ftr_ext_fold_consistent_ty),
1590        ("Functor.Ext.FoldmapMorphism", ftr_ext_foldmap_morphism_ty),
1591        (
1592            "Functor.Ext.RepresentableTabulate",
1593            ftr_ext_representable_tabulate_ty,
1594        ),
1595        (
1596            "Functor.Ext.RepresentableIndex",
1597            ftr_ext_representable_index_ty,
1598        ),
1599        ("Functor.Ext.KanLeft", ftr_ext_kan_left_ty),
1600        ("Functor.Ext.KanRight", ftr_ext_kan_right_ty),
1601        ("Functor.Ext.DayConvUnit", ftr_ext_day_conv_unit_ty),
1602        ("Functor.Ext.DayConvAssoc", ftr_ext_day_conv_assoc_ty),
1603        ("Functor.Ext.ComposeIdentity", ftr_ext_compose_identity_ty),
1604        ("Functor.Ext.ComposeAssoc", ftr_ext_compose_assoc_ty),
1605        ("Functor.Ext.NatTransId", ftr_ext_nat_trans_id_ty),
1606        ("Functor.Ext.NatTransComp", ftr_ext_nat_trans_comp_ty),
1607        ("Functor.Ext.AdjunctionUnit", ftr_ext_adjunction_unit_ty),
1608        ("Functor.Ext.AdjunctionCounit", ftr_ext_adjunction_counit_ty),
1609        (
1610            "Functor.Ext.AdjunctionTriangle",
1611            ftr_ext_adjunction_triangle_ty,
1612        ),
1613        ("Functor.Ext.FunctorCatObj", ftr_ext_functor_cat_obj_ty),
1614        ("Functor.Ext.FunctorCatMor", ftr_ext_functor_cat_mor_ty),
1615        ("Functor.Ext.Presheaf", ftr_ext_presheaf_ty),
1616        ("Functor.Ext.YonedaLemma", ftr_ext_yoneda_lemma_ty),
1617        ("Functor.Ext.YonedaEmbedding", ftr_ext_yoneda_embedding_ty),
1618        ("Functor.Ext.SheafGluing", ftr_ext_sheaf_gluing_ty),
1619        ("Functor.Ext.SheafLocality", ftr_ext_sheaf_locality_ty),
1620        ("Functor.Ext.FmapPreservesEq", ftr_ext_fmap_preserves_eq_ty),
1621        ("Functor.Ext.FreeFunctor", ftr_ext_free_functor_ty),
1622        ("Functor.Ext.CofreeFunctor", ftr_ext_cofree_functor_ty),
1623        (
1624            "Functor.Ext.ExponentialFunctor",
1625            ftr_ext_exponential_functor_ty,
1626        ),
1627    ];
1628    for (name, ty_fn) in axioms {
1629        let _ = env.add(Declaration::Axiom {
1630            name: Name::str(*name),
1631            univ_params: vec![],
1632            ty: ty_fn(),
1633        });
1634    }
1635}
1636/// Kleisli composition for Option monad.
1637pub fn kleisli_compose_option<A, B, C, F, G>(f: F, g: G) -> impl Fn(A) -> Option<C>
1638where
1639    F: Fn(A) -> Option<B>,
1640    G: Fn(B) -> Option<C>,
1641{
1642    move |a| f(a).and_then(|b| g(b))
1643}
1644/// Kleisli composition for Vec monad (list monad).
1645pub fn kleisli_compose_vec<A, B, C, F, G>(f: F, g: G) -> impl Fn(A) -> Vec<C>
1646where
1647    F: Fn(A) -> Vec<B>,
1648    G: Fn(B) -> Vec<C>,
1649    B: Clone,
1650{
1651    move |a| f(a).into_iter().flat_map(|b| g(b)).collect()
1652}
1653/// Lift a function into the Reader functor.
1654pub fn reader_fmap<E: Clone + 'static, A: 'static, B: 'static>(
1655    reader: Reader<E, A>,
1656    f: impl Fn(A) -> B + 'static,
1657) -> Reader<E, B> {
1658    reader.map(f)
1659}
1660/// Dimap for a function (profunctor instance for Fn).
1661pub fn dimap_fn<A, B, C, D>(
1662    pre: impl Fn(C) -> A + 'static,
1663    post: impl Fn(B) -> D + 'static,
1664    f: impl Fn(A) -> B + 'static,
1665) -> impl Fn(C) -> D {
1666    move |c| post(f(pre(c)))
1667}
1668/// Apply a natural transformation option_to_vec then fmap.
1669pub fn fmap_via_nat_trans<A: Clone, B, F: Fn(A) -> B>(v: Option<A>, f: F) -> Vec<B> {
1670    option_to_vec(v).into_iter().map(f).collect()
1671}
1672/// Sequence Option<Vec<A>> — swap the two functors.
1673pub fn sequence_option_vec<A: Clone>(xs: Vec<Option<A>>) -> Option<Vec<A>> {
1674    xs.into_iter().collect()
1675}
1676/// Map with two effects: Option then Vec.
1677pub fn fmap_option_then_vec<A, B: Clone, F: Fn(A) -> B>(opt: Option<A>, f: F) -> Vec<B> {
1678    match opt {
1679        Some(a) => vec![f(a)],
1680        None => vec![],
1681    }
1682}
1683/// Pure for the Option applicative.
1684pub fn pure_option<A>(a: A) -> Option<A> {
1685    Some(a)
1686}
1687/// Pure for the Vec applicative.
1688pub fn pure_vec<A>(a: A) -> Vec<A> {
1689    vec![a]
1690}
1691/// Left-to-right Kleisli fish operator for Option.
1692pub fn fish_option<A, B, C>(
1693    f: impl Fn(A) -> Option<B>,
1694    g: impl Fn(B) -> Option<C>,
1695    a: A,
1696) -> Option<C> {
1697    f(a).and_then(g)
1698}
1699/// Monoidal product for Options: pair them up.
1700pub fn option_zip<A, B>(a: Option<A>, b: Option<B>) -> Option<(A, B)> {
1701    match (a, b) {
1702        (Some(x), Some(y)) => Some((x, y)),
1703        _ => None,
1704    }
1705}
1706/// Day convolution combinator on Vec.
1707pub fn day_conv_vec<A: Clone, B: Clone, C>(
1708    fa: Vec<A>,
1709    fb: Vec<B>,
1710    combine: impl Fn(A, B) -> C,
1711) -> Vec<C> {
1712    let mut result = Vec::new();
1713    for a in fa {
1714        for b in fb.iter().cloned() {
1715            result.push(combine(a.clone(), b));
1716        }
1717    }
1718    result
1719}
1720/// Cofunctor (contravariant) composition.
1721pub fn contramap_compose<A: 'static, B: 'static, C: 'static>(
1722    pred: Pred<A>,
1723    f: impl Fn(B) -> A + 'static,
1724    g: impl Fn(C) -> B + 'static,
1725) -> Pred<C> {
1726    pred.contramap(move |c| f(g(c)))
1727}
1728/// Check the profunctor identity law for functions.
1729pub fn profunctor_identity_law<A: Clone + PartialEq>(
1730    f: impl Fn(A) -> A + Clone + 'static,
1731    x: A,
1732) -> bool {
1733    let f2 = f.clone();
1734    let dimapped = dimap_fn(|a: A| a, |a: A| a, f2);
1735    dimapped(x.clone()) == f(x)
1736}
1737/// Functor composition: apply outer fmap then inner fmap.
1738pub fn double_fmap<A, B, C>(
1739    xs: Vec<Option<A>>,
1740    f: impl Fn(A) -> B,
1741    g: impl Fn(B) -> C,
1742) -> Vec<Option<C>> {
1743    xs.into_iter().map(|opt| opt.map(|a| g(f(a)))).collect()
1744}
1745/// Check adjunction triangle law (L ⊣ R): (ε L) ∘ (L η) = id.
1746/// Approximated as: round-trip through Option is identity.
1747pub fn adjunction_triangle_option<A: Clone + PartialEq>(a: A) -> bool {
1748    let unit = |x: A| Some(x);
1749    let counit = |opt: Option<A>| opt.expect("unit always produces Some, so counit receives Some");
1750    counit(unit(a.clone())) == a
1751}
1752/// Yoneda reduction: Nat(Hom(A, –), F) ≅ F A.
1753/// Approximated by showing that applying fmap id to a value is identity.
1754pub fn yoneda_reduction<A: Clone + PartialEq>(fa: Option<A>) -> bool {
1755    fmap_option(fa.clone(), |a| a) == fa
1756}
1757/// Left Kan extension approximation: extend f along k using Vec.
1758pub fn lan_approximation<A: Clone, B: Clone, C>(
1759    k: impl Fn(A) -> B,
1760    f: impl Fn(A) -> C,
1761    xs: Vec<A>,
1762) -> Vec<C> {
1763    xs.into_iter()
1764        .map(|a| {
1765            let _ = k(a.clone());
1766            f(a)
1767        })
1768        .collect()
1769}
1770/// Check sheaf gluing: two compatible sections glue uniquely.
1771/// Approximated: merging two Option sections.
1772pub fn sheaf_glue_option<A: Clone + PartialEq>(s1: Option<A>, s2: Option<A>) -> Option<A> {
1773    match (s1, s2) {
1774        (Some(a), None) => Some(a),
1775        (None, Some(b)) => Some(b),
1776        (Some(a), Some(_)) => Some(a),
1777        (None, None) => None,
1778    }
1779}
1780/// Representable functor: tabulate then index roundtrip.
1781pub fn representable_roundtrip<A: Clone + PartialEq>(
1782    n: usize,
1783    f: impl Fn(usize) -> A,
1784    i: usize,
1785) -> bool {
1786    let rep = RepresentableFunctorExt::tabulate(n, &f);
1787    if i < n {
1788        rep.index(i).cloned() == Some(f(i))
1789    } else {
1790        rep.index(i).is_none()
1791    }
1792}
1793/// Check Day convolution unit law: Day(F, Id) ≅ F.
1794pub fn day_conv_unit_vec<A: Clone + PartialEq>(fa: Vec<A>) -> bool {
1795    let id_unit: Vec<()> = vec![()];
1796    let result: Vec<A> = day_conv_vec(fa.clone(), id_unit, |a, _| a);
1797    result == fa
1798}