use super::functions::*;
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct Futumorphism {
pub coalgebra_name: String,
}
#[allow(dead_code)]
impl Futumorphism {
pub fn new(coalgebra_name: &str) -> Self {
Self {
coalgebra_name: coalgebra_name.to_string(),
}
}
pub fn interleave<A: Clone>(xs: &[A], ys: &[A]) -> Vec<A> {
let mut result = Vec::new();
for i in 0..xs.len().max(ys.len()) {
if i < xs.len() {
result.push(xs[i].clone());
}
if i < ys.len() {
result.push(ys[i].clone());
}
}
result
}
}
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct DefunctClosure {
pub tag: String,
pub free_variables: Vec<(String, String)>,
pub apply_case: String,
}
#[allow(dead_code)]
impl DefunctClosure {
pub fn new(tag: &str, free_vars: Vec<(&str, &str)>, apply: &str) -> Self {
Self {
tag: tag.to_string(),
free_variables: free_vars
.iter()
.map(|(n, t)| (n.to_string(), t.to_string()))
.collect(),
apply_case: apply.to_string(),
}
}
pub fn arity(&self) -> usize {
self.free_variables.len()
}
pub fn apply_description(&self) -> String {
format!("apply({}) = {}", self.tag, self.apply_case)
}
}
#[derive(Clone)]
pub struct Zipper<A> {
pub left: Vec<A>,
pub focus: A,
pub right: Vec<A>,
}
impl<A: Clone> Zipper<A> {
pub fn new(data: Vec<A>, i: usize) -> Option<Self> {
if data.is_empty() || i >= data.len() {
return None;
}
let mut v = data;
let right = v.split_off(i + 1);
let focus = v
.pop()
.expect("v is non-empty: i < data.len() and v is data[..=i]");
Some(Self {
left: v,
focus,
right,
})
}
pub fn extract(&self) -> &A {
&self.focus
}
pub fn extend<B: Clone>(&self, f: impl Fn(&Zipper<A>) -> B) -> Zipper<B> {
let all: Vec<A> = self
.left
.iter()
.cloned()
.chain(std::iter::once(self.focus.clone()))
.chain(self.right.iter().cloned())
.collect();
let focus_idx = self.left.len();
let results: Vec<B> = (0..all.len())
.map(|i| {
let z = Zipper::new(all.clone(), i)
.expect("i < all.len(): iterating over 0..all.len()");
f(&z)
})
.collect();
Zipper::new(results, focus_idx).expect(
"focus_idx < results.len(): focus_idx == left.len() < all.len() == results.len()",
)
}
pub fn move_left(&self) -> Option<Zipper<A>> {
if self.left.is_empty() {
return None;
}
let mut new_left = self.left.clone();
let new_focus = new_left
.pop()
.expect("new_left is non-empty: left is non-empty, checked by early return");
let mut new_right = vec![self.focus.clone()];
new_right.extend(self.right.iter().cloned());
Some(Zipper {
left: new_left,
focus: new_focus,
right: new_right,
})
}
pub fn move_right(&self) -> Option<Zipper<A>> {
if self.right.is_empty() {
return None;
}
let mut new_right = self.right.clone();
let new_focus = new_right.remove(0);
let mut new_left = self.left.clone();
new_left.push(self.focus.clone());
Some(Zipper {
left: new_left,
focus: new_focus,
right: new_right,
})
}
pub fn to_vec(&self) -> Vec<A> {
self.left
.iter()
.cloned()
.chain(std::iter::once(self.focus.clone()))
.chain(self.right.iter().cloned())
.collect()
}
pub fn len(&self) -> usize {
self.left.len() + 1 + self.right.len()
}
pub fn is_empty(&self) -> bool {
false
}
pub fn is_singleton(&self) -> bool {
self.left.is_empty() && self.right.is_empty()
}
}
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct Apomorphism {
pub coalgebra_name: String,
}
#[allow(dead_code)]
impl Apomorphism {
pub fn new(coalgebra_name: &str) -> Self {
Self {
coalgebra_name: coalgebra_name.to_string(),
}
}
pub fn insert_sorted(mut xs: Vec<i64>, x: i64) -> Vec<i64> {
let pos = xs.partition_point(|&v| v <= x);
xs.insert(pos, x);
xs
}
}
#[allow(dead_code)]
pub struct ChurchNumerals;
#[allow(dead_code)]
impl ChurchNumerals {
pub fn church_zero_desc() -> &'static str {
"λf. λx. x"
}
pub fn church_succ_desc() -> &'static str {
"λn. λf. λx. f (n f x)"
}
pub fn church_to_u64(n: u64) -> u64 {
n
}
pub fn church_add(m: u64, n: u64) -> u64 {
m + n
}
pub fn church_mul(m: u64, n: u64) -> u64 {
m * n
}
pub fn church_pow(m: u64, n: u64) -> u64 {
m.pow(n as u32)
}
}
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct TraversableData {
pub container_type: String,
pub traverse_type: String,
pub is_foldable: bool,
pub naturality_condition: String,
}
#[allow(dead_code)]
impl TraversableData {
pub fn list_traversable() -> Self {
TraversableData {
container_type: "List".to_string(),
traverse_type: "Applicative f => (a -> f b) -> [a] -> f [b]".to_string(),
is_foldable: true,
naturality_condition: "t . traverse g = traverse (t . g)".to_string(),
}
}
pub fn map_traversable() -> Self {
TraversableData {
container_type: "Map k".to_string(),
traverse_type: "Applicative f => (a -> f b) -> Map k a -> f (Map k b)".to_string(),
is_foldable: true,
naturality_condition: "t . traverse g = traverse (t . g)".to_string(),
}
}
pub fn laws(&self) -> Vec<String> {
vec![
"Naturality: t . traverse f = traverse (t . f) for natural t".to_string(),
"Identity: traverse Identity = Identity".to_string(),
"Composition: traverse (Compose . fmap g . f) = Compose . fmap (traverse g) . traverse f"
.to_string(),
]
}
pub fn efficient_mapaccum(&self) -> String {
format!(
"mapAccumL/R for {}: O(n) traversal with accumulated state",
self.container_type
)
}
}
pub struct Traversal<S, A> {
to_list: Box<dyn Fn(&S) -> Vec<A>>,
from_list: Box<dyn Fn(Vec<A>, &S) -> S>,
}
impl<S: 'static + Clone, A: 'static + Clone> Traversal<S, A> {
pub fn new(
to_list: impl Fn(&S) -> Vec<A> + 'static,
from_list: impl Fn(Vec<A>, &S) -> S + 'static,
) -> Self {
Self {
to_list: Box::new(to_list),
from_list: Box::new(from_list),
}
}
pub fn view(&self, s: &S) -> Vec<A> {
(self.to_list)(s)
}
pub fn over(&self, f: impl Fn(A) -> A, s: S) -> S {
let vals: Vec<A> = (self.to_list)(&s).into_iter().map(&f).collect();
(self.from_list)(vals, &s)
}
}
pub struct RecursionSchemeEval;
impl RecursionSchemeEval {
pub fn cata<A, B>(tree: RoseTree<A>, alg: &dyn Fn(A, Vec<B>) -> B) -> B {
match tree {
RoseTree::Node(a, children) => {
let results: Vec<B> = children.into_iter().map(|c| Self::cata(c, alg)).collect();
alg(a, results)
}
}
}
pub fn ana<A, S: Clone>(seed: S, coalg: &dyn Fn(S) -> (A, Vec<S>)) -> RoseTree<A> {
let (a, children) = coalg(seed);
let subtrees = children.into_iter().map(|s| Self::ana(s, coalg)).collect();
RoseTree::Node(a, subtrees)
}
pub fn hylo<A, B, S: Clone>(
seed: S,
coalg: &dyn Fn(S) -> (A, Vec<S>),
alg: &dyn Fn(A, Vec<B>) -> B,
) -> B {
let (a, children) = coalg(seed);
let results: Vec<B> = children
.into_iter()
.map(|s| Self::hylo(s, coalg, alg))
.collect();
alg(a, results)
}
}
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct Paramorphism {
pub algebra_name: String,
}
#[allow(dead_code)]
impl Paramorphism {
pub fn new(algebra_name: &str) -> Self {
Self {
algebra_name: algebra_name.to_string(),
}
}
pub fn factorial_para(n: u64) -> u64 {
(1..=n).product()
}
pub fn tails_para<A: Clone>(xs: &[A]) -> Vec<Vec<A>> {
(0..=xs.len()).map(|i| xs[i..].to_vec()).collect()
}
}
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct ReaderMonad<R: Clone, A: Clone> {
_phantom_r: std::marker::PhantomData<R>,
_phantom_a: std::marker::PhantomData<A>,
pub description: String,
}
#[allow(dead_code)]
impl<R: Clone, A: Clone> ReaderMonad<R, A> {
pub fn new(desc: &str) -> Self {
Self {
_phantom_r: std::marker::PhantomData,
_phantom_a: std::marker::PhantomData,
description: desc.to_string(),
}
}
pub fn ask_desc(&self) -> String {
format!("ask :: Reader {}", std::any::type_name::<R>())
}
pub fn local_desc(&self) -> String {
format!(
"local :: ({0} -> {0}) -> Reader {0} _",
std::any::type_name::<R>()
)
}
}
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct ArrowData {
pub arrow_name: String,
pub arr_type: String,
pub compose_type: String,
pub first_type: String,
pub is_arrowchoice: bool,
pub is_arrowloop: bool,
}
#[allow(dead_code)]
impl ArrowData {
pub fn function_arrow() -> Self {
ArrowData {
arrow_name: "->".to_string(),
arr_type: "(b -> c) -> Arrow b c".to_string(),
compose_type: "Arrow b c -> Arrow c d -> Arrow b d".to_string(),
first_type: "Arrow b c -> Arrow (b, d) (c, d)".to_string(),
is_arrowchoice: true,
is_arrowloop: true,
}
}
pub fn kleisli_arrow(monad: &str) -> Self {
ArrowData {
arrow_name: format!("Kleisli {}", monad),
arr_type: format!("(b -> {} c) -> Kleisli {} b c", monad, monad),
compose_type: format!(
"Kleisli {} b c -> Kleisli {} c d -> Kleisli {} b d",
monad, monad, monad
),
first_type: format!("Kleisli {} b c -> Kleisli {} (b,d) (c,d)", monad, monad),
is_arrowchoice: false,
is_arrowloop: false,
}
}
pub fn hughes_laws(&self) -> Vec<String> {
vec![
"arr id = id".to_string(),
"arr (f . g) = arr f . arr g".to_string(),
"first (arr f) = arr (f *** id)".to_string(),
"first (f . g) = first f . first g".to_string(),
]
}
pub fn freyd_category_connection(&self) -> String {
"Arrows generalize Freyd categories (Power-Thielecke): model effectful computations"
.to_string()
}
}
pub struct HMap {
entries: Vec<(String, Box<dyn std::any::Any>)>,
}
impl HMap {
pub fn new() -> Self {
Self {
entries: Vec::new(),
}
}
pub fn insert<V: 'static>(&mut self, key: impl Into<String>, value: V) {
self.entries.push((key.into(), Box::new(value)));
}
pub fn get<V: 'static>(&self, key: &str) -> Option<&V> {
self.entries
.iter()
.find(|(k, _)| k == key)
.and_then(|(_, v)| v.downcast_ref::<V>())
}
pub fn len(&self) -> usize {
self.entries.len()
}
pub fn is_empty(&self) -> bool {
self.entries.is_empty()
}
}
pub struct Prism<S, A> {
preview: Box<dyn Fn(S) -> Option<A>>,
review: Box<dyn Fn(A) -> S>,
}
impl<S: 'static, A: 'static> Prism<S, A> {
pub fn new(
preview: impl Fn(S) -> Option<A> + 'static,
review: impl Fn(A) -> S + 'static,
) -> Self {
Self {
preview: Box::new(preview),
review: Box::new(review),
}
}
pub fn preview(&self, s: S) -> Option<A> {
(self.preview)(s)
}
pub fn review(&self, a: A) -> S {
(self.review)(a)
}
}
#[allow(dead_code)]
pub enum ConsoleProg<A> {
Done(A),
Step(ConsoleEffect, Box<dyn FnOnce(String) -> ConsoleProg<A>>),
}
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct StateMonad<S: Clone, A: Clone> {
_phantom_s: std::marker::PhantomData<S>,
_phantom_a: std::marker::PhantomData<A>,
pub description: String,
}
#[allow(dead_code)]
impl<S: Clone, A: Clone> StateMonad<S, A> {
pub fn new(description: &str) -> Self {
Self {
_phantom_s: std::marker::PhantomData,
_phantom_a: std::marker::PhantomData,
description: description.to_string(),
}
}
pub fn get_desc(&self) -> String {
format!(
"get :: State {} {}",
std::any::type_name::<S>(),
std::any::type_name::<A>()
)
}
pub fn put_desc(&self) -> String {
format!(
"put :: {} -> State {} ()",
std::any::type_name::<S>(),
std::any::type_name::<S>()
)
}
pub fn modify_desc(&self) -> String {
format!(
"modify :: ({0} -> {0}) -> State {0} ()",
std::any::type_name::<S>()
)
}
}
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct DependentTypeExample {
pub type_name: String,
pub type_signature: String,
pub invariant: String,
pub language: String,
}
#[allow(dead_code)]
impl DependentTypeExample {
pub fn fixed_length_vector(elem_type: &str, n: usize) -> Self {
DependentTypeExample {
type_name: format!("Vec {} {}", elem_type, n),
type_signature: format!("Vec : Type -> â„• -> Type"),
invariant: format!("length is exactly {}", n),
language: "Agda/Idris/Lean".to_string(),
}
}
pub fn sorted_list(elem_type: &str) -> Self {
DependentTypeExample {
type_name: format!("SortedList {}", elem_type),
type_signature: "SortedList : Type -> Type".to_string(),
invariant: "all elements in sorted order".to_string(),
language: "Agda".to_string(),
}
}
pub fn fin_type(n: usize) -> Self {
DependentTypeExample {
type_name: format!("Fin {}", n),
type_signature: "Fin : â„• -> Type".to_string(),
invariant: format!("indices in {{0,..,{}}}", n.saturating_sub(1)),
language: "Agda/Lean".to_string(),
}
}
pub fn type_safety_guarantee(&self) -> String {
format!(
"{}: type system enforces '{}' statically (no runtime check needed)",
self.type_name, self.invariant
)
}
pub fn extraction_to_code(&self) -> String {
format!(
"From {} proof to certified {} code via extraction",
self.language, self.language
)
}
}
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub enum FreeApplicative<A: Clone> {
Pure(A),
Ap(usize, Box<FreeApplicative<A>>),
}
#[allow(dead_code)]
impl<A: Clone> FreeApplicative<A> {
pub fn pure_val(a: A) -> Self {
FreeApplicative::Pure(a)
}
pub fn depth(&self) -> usize {
match self {
FreeApplicative::Pure(_) => 0,
FreeApplicative::Ap(_, x) => 1 + x.depth(),
}
}
}
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct Histomorphism {
pub algebra_name: String,
pub cache: Vec<i64>,
}
#[allow(dead_code)]
impl Histomorphism {
pub fn new(algebra_name: &str) -> Self {
Self {
algebra_name: algebra_name.to_string(),
cache: Vec::new(),
}
}
pub fn fibonacci_histo(&mut self, n: usize) -> i64 {
for i in self.cache.len()..=n {
let v = if i == 0 {
0
} else if i == 1 {
1
} else {
self.cache[i - 1] + self.cache[i - 2]
};
self.cache.push(v);
}
self.cache[n]
}
}
pub enum Effect<E, A> {
Pure(A),
Perform(E, Box<dyn FnOnce(()) -> Effect<E, A>>),
}
impl<E: 'static, A: 'static> Effect<E, A> {
pub fn pure(a: A) -> Self {
Effect::Pure(a)
}
pub fn handle(self, handler: &dyn Fn(E)) -> A
where
A: Default,
{
match self {
Effect::Pure(a) => a,
Effect::Perform(e, k) => {
handler(e);
k(()).handle(handler)
}
}
}
}
pub struct ComonadExtend;
impl ComonadExtend {
pub fn extend<A: Clone, B: Clone>(z: &Zipper<A>, f: impl Fn(&Zipper<A>) -> B) -> Zipper<B> {
z.extend(f)
}
pub fn duplicate<A: Clone>(z: &Zipper<A>) -> Zipper<Zipper<A>> {
z.extend(|sub_z| {
let left = sub_z.left.clone();
let focus = sub_z.focus.clone();
let right = sub_z.right.clone();
Zipper { left, focus, right }
})
}
}
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct Hylomorphism {
pub seed_label: String,
pub unfold_steps: Vec<String>,
pub fold_steps: Vec<String>,
}
#[allow(dead_code)]
impl Hylomorphism {
pub fn new(seed_label: &str) -> Self {
Self {
seed_label: seed_label.to_string(),
unfold_steps: Vec::new(),
fold_steps: Vec::new(),
}
}
pub fn add_unfold_step(mut self, step: &str) -> Self {
self.unfold_steps.push(step.to_string());
self
}
pub fn add_fold_step(mut self, step: &str) -> Self {
self.fold_steps.push(step.to_string());
self
}
pub fn fibonacci_hylo(n: u32) -> u64 {
fn fib(n: u32) -> u64 {
if n <= 1 {
return n as u64;
}
let mut a = 0u64;
let mut b = 1u64;
for _ in 2..=n {
let c = a + b;
a = b;
b = c;
}
b
}
fib(n)
}
}
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct EffectSystem {
pub effect_name: String,
pub operations: Vec<(String, String)>,
pub handler_type: String,
}
#[allow(dead_code)]
impl EffectSystem {
pub fn state(state_type: &str) -> Self {
Self {
effect_name: format!("State({})", state_type),
operations: vec![
("get".to_string(), format!("unit -> {}", state_type)),
("put".to_string(), format!("{} -> unit", state_type)),
],
handler_type: format!("{} -> a -> ({} * {})", state_type, state_type, "a"),
}
}
pub fn exception(exc_type: &str) -> Self {
Self {
effect_name: format!("Exception({})", exc_type),
operations: vec![("throw".to_string(), format!("{} -> a", exc_type))],
handler_type: format!("({} -> b) -> (a -> b) -> b", exc_type),
}
}
pub fn num_ops(&self) -> usize {
self.operations.len()
}
}
pub struct ProfunctorOptic<S, T, A, B> {
run: Box<dyn Fn(Box<dyn Fn(A) -> B>) -> Box<dyn Fn(S) -> T>>,
}
impl<S: 'static, T: 'static, A: 'static, B: 'static> ProfunctorOptic<S, T, A, B> {
pub fn new(run: impl Fn(Box<dyn Fn(A) -> B>) -> Box<dyn Fn(S) -> T> + 'static) -> Self {
Self { run: Box::new(run) }
}
pub fn apply(&self, f: impl Fn(A) -> B + 'static) -> Box<dyn Fn(S) -> T> {
(self.run)(Box::new(f))
}
pub fn lens_optic(
getter: impl Fn(&S) -> A + 'static,
setter: impl Fn(B, S) -> T + 'static,
) -> Self
where
S: Clone + 'static,
{
let getter = std::sync::Arc::new(getter);
let setter = std::sync::Arc::new(setter);
Self::new(move |f: Box<dyn Fn(A) -> B>| {
let getter = getter.clone();
let setter = setter.clone();
let f = std::sync::Arc::new(f);
Box::new(move |s: S| {
let a = getter(&s);
let b = f(a);
setter(b, s)
})
})
}
pub fn prism_optic(
preview: impl Fn(S) -> Result<A, T> + 'static,
review: impl Fn(B) -> T + 'static,
) -> Self
where
S: 'static,
{
let preview = std::sync::Arc::new(preview);
let review = std::sync::Arc::new(review);
Self::new(move |f: Box<dyn Fn(A) -> B>| {
let preview = preview.clone();
let review = review.clone();
let f = std::sync::Arc::new(f);
Box::new(move |s: S| match preview(s) {
Ok(a) => review(f(a)),
Err(t) => t,
})
})
}
}
pub enum HList {
Nil,
Cons(Box<dyn std::any::Any>, Box<HList>),
}
impl HList {
pub fn nil() -> Self {
HList::Nil
}
pub fn cons<T: 'static>(head: T, tail: HList) -> Self {
HList::Cons(Box::new(head), Box::new(tail))
}
pub fn len(&self) -> usize {
match self {
HList::Nil => 0,
HList::Cons(_, tail) => 1 + tail.len(),
}
}
pub fn is_empty(&self) -> bool {
matches!(self, HList::Nil)
}
}
#[allow(dead_code)]
pub enum RoseTree<A> {
Node(A, Vec<RoseTree<A>>),
}
pub struct TypeEquality<S, T> {
_coerce: std::marker::PhantomData<(S, T)>,
}
impl<T> TypeEquality<T, T> {
pub fn refl() -> Self {
TypeEquality {
_coerce: std::marker::PhantomData,
}
}
}
impl<S, T> TypeEquality<S, T> {
pub fn coerce(self, s: S) -> T
where
S: Into<T>,
{
s.into()
}
}
pub struct LensComposer;
impl LensComposer {
pub fn compose<S, M, A>(outer: Lens<S, M>, inner: Lens<M, A>) -> impl Fn(&S) -> A
where
S: Clone + 'static,
M: Clone + 'static,
A: Clone + 'static,
{
move |s: &S| {
let m = outer.view(s);
inner.view(&m)
}
}
pub fn check_get_set<S, A>(lens: &Lens<S, A>, s: S) -> bool
where
S: Clone + PartialEq + 'static,
A: Clone + 'static,
{
let a = lens.view(&s);
let s2 = lens.set(a, s.clone());
s2 == s
}
pub fn check_set_get<S, A>(lens: &Lens<S, A>, a: A, s: S) -> bool
where
S: Clone + 'static,
A: Clone + PartialEq + 'static,
{
let s2 = lens.set(a.clone(), s);
let a2 = lens.view(&s2);
a2 == a
}
pub fn check_set_set<S, A>(lens: &Lens<S, A>, a1: A, a2: A, s: S) -> bool
where
S: Clone + PartialEq + 'static,
A: Clone + 'static,
{
let s_after_a1 = lens.set(a1, s.clone());
let s_after_a2_a1 = lens.set(a2.clone(), s_after_a1);
let s_after_a2 = lens.set(a2, s);
s_after_a2_a1 == s_after_a2
}
}
pub struct Coerce<S, T> {
_marker: std::marker::PhantomData<(S, T)>,
}
impl<S: 'static, T: 'static> Coerce<S, T> {
pub fn try_coerce(s: S) -> Option<T> {
let boxed: Box<dyn std::any::Any> = Box::new(s);
boxed.downcast::<T>().ok().map(|b| *b)
}
}
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct FreeMonadInfo {
pub functor_name: String,
pub operations: Vec<String>,
pub description: String,
}
#[allow(dead_code)]
impl FreeMonadInfo {
pub fn over(functor: &str, ops: Vec<&str>) -> Self {
Self {
functor_name: functor.to_string(),
operations: ops.iter().map(|s| s.to_string()).collect(),
description: format!("Free monad over {} with {} operations", functor, ops.len()),
}
}
pub fn interpreter_description(&self) -> String {
format!(
"foldFree :: ({} a -> m a) -> Free {} a -> m a",
self.functor_name, self.functor_name
)
}
pub fn num_operations(&self) -> usize {
self.operations.len()
}
}
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct CpsTransform {
pub source_type: String,
pub result_type: String,
pub continuation_type: String,
}
#[allow(dead_code)]
impl CpsTransform {
pub fn new(source: &str, result: &str) -> Self {
Self {
source_type: source.to_string(),
result_type: result.to_string(),
continuation_type: format!("({} -> {}) -> {}", source, result, result),
}
}
pub fn transform_description(&self) -> String {
format!("CPS[{}] = ({})", self.source_type, self.continuation_type)
}
}
#[allow(dead_code)]
pub struct ScottEncoding;
#[allow(dead_code)]
impl ScottEncoding {
pub fn scott_true_desc() -> &'static str {
"λt. λf. t"
}
pub fn scott_false_desc() -> &'static str {
"λt. λf. f"
}
pub fn scott_pair_desc() -> &'static str {
"λa. λb. λs. s a b"
}
pub fn scott_fst_desc() -> &'static str {
"λp. p (λa. λb. a)"
}
pub fn scott_nil_desc() -> &'static str {
"λn. λc. n"
}
pub fn scott_cons_desc() -> &'static str {
"λh. λt. λn. λc. c h t"
}
}
pub struct Lens<S, A> {
getter: Box<dyn Fn(&S) -> A>,
setter: Box<dyn Fn(A, S) -> S>,
}
impl<S: 'static, A: 'static> Lens<S, A> {
pub fn new(getter: impl Fn(&S) -> A + 'static, setter: impl Fn(A, S) -> S + 'static) -> Self {
Self {
getter: Box::new(getter),
setter: Box::new(setter),
}
}
pub fn view(&self, s: &S) -> A {
(self.getter)(s)
}
pub fn set(&self, a: A, s: S) -> S {
(self.setter)(a, s)
}
pub fn over(&self, f: impl Fn(A) -> A, s: S) -> S
where
S: Clone,
{
let a = self.view(&s);
self.set(f(a), s)
}
}
#[allow(dead_code)]
pub struct BoehmBerarducci;
#[allow(dead_code)]
impl BoehmBerarducci {
pub fn bb_nat_type_desc() -> &'static str {
"forall r. r -> (r -> r) -> r"
}
pub fn bb_list_type_desc() -> &'static str {
"forall r. r -> (a -> r -> r) -> r"
}
pub fn bb_tree_type_desc() -> &'static str {
"forall r. (a -> List r -> r) -> r"
}
}
pub struct Iso<S, A> {
to: Box<dyn Fn(S) -> A>,
from: Box<dyn Fn(A) -> S>,
}
impl<S: 'static, A: 'static> Iso<S, A> {
pub fn new(to: impl Fn(S) -> A + 'static, from: impl Fn(A) -> S + 'static) -> Self {
Self {
to: Box::new(to),
from: Box::new(from),
}
}
pub fn view(&self, s: S) -> A {
(self.to)(s)
}
pub fn review(&self, a: A) -> S {
(self.from)(a)
}
pub fn get(&self, s: S) -> A {
(self.to)(s)
}
}
pub struct EffectHandler<E, A, B> {
handle_fn: Box<dyn Fn(E, Box<dyn FnOnce(A) -> B>) -> B>,
}
impl<E: 'static, A: 'static, B: 'static> EffectHandler<E, A, B> {
pub fn new(handle_fn: impl Fn(E, Box<dyn FnOnce(A) -> B>) -> B + 'static) -> Self {
Self {
handle_fn: Box::new(handle_fn),
}
}
pub fn run(&self, effect: E, continuation: impl FnOnce(A) -> B + 'static) -> B {
(self.handle_fn)(effect, Box::new(continuation))
}
}
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct YonedaEmbedding<A: Clone> {
pub object: A,
pub morphism_count: usize,
}
#[allow(dead_code)]
impl<A: Clone> YonedaEmbedding<A> {
pub fn new(object: A) -> Self {
Self {
object,
morphism_count: 0,
}
}
pub fn add_morphism(mut self) -> Self {
self.morphism_count += 1;
self
}
}
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct HomotopyEquivalence {
pub type_a: String,
pub type_b: String,
pub forth_map: String,
pub back_map: String,
pub is_univalent: bool,
}
#[allow(dead_code)]
impl HomotopyEquivalence {
pub fn new(a: &str, b: &str, f: &str, g: &str) -> Self {
HomotopyEquivalence {
type_a: a.to_string(),
type_b: b.to_string(),
forth_map: f.to_string(),
back_map: g.to_string(),
is_univalent: false,
}
}
pub fn univalent_equivalence(mut self) -> Self {
self.is_univalent = true;
self
}
pub fn contractibility_condition(&self) -> String {
format!(
"{} ≃ {}: ∃ f:{}->{}, g:{}->{}, f∘g∼id, g∘f∼id",
self.type_a, self.type_b, self.type_a, self.type_b, self.type_b, self.type_a
)
}
pub fn univalence_axiom(&self) -> String {
if self.is_univalent {
"(A=B) ≃ (A≃B) (Voevodsky's univalence axiom)".to_string()
} else {
"Not using univalence axiom".to_string()
}
}
}
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct Cont<R: Clone, A: Clone> {
_phantom_r: std::marker::PhantomData<R>,
_phantom_a: std::marker::PhantomData<A>,
pub label: String,
}
#[allow(dead_code)]
impl<R: Clone, A: Clone> Cont<R, A> {
pub fn new(label: &str) -> Self {
Self {
_phantom_r: std::marker::PhantomData,
_phantom_a: std::marker::PhantomData,
label: label.to_string(),
}
}
pub fn run_cont_desc(&self) -> String {
format!("Cont({}).run_cont", self.label)
}
}
pub enum FreeMonad<A> {
Pure(A),
Free(Box<dyn FnOnce() -> FreeMonad<A>>),
}
impl<A> FreeMonad<A> {
pub fn pure(a: A) -> Self {
FreeMonad::Pure(a)
}
pub fn fold<B>(self, pure_fn: impl Fn(A) -> B, free_fn: impl Fn(FreeMonad<A>) -> B) -> B {
match self {
FreeMonad::Pure(a) => pure_fn(a),
FreeMonad::Free(mk) => free_fn(mk()),
}
}
}
#[allow(dead_code)]
pub enum ConsoleEffect {
Print(String),
Read,
}
pub struct FreeMonadInterpreter;
impl FreeMonadInterpreter {
pub fn run<A>(
prog: ConsoleProg<A>,
print_handler: &mut dyn FnMut(&str),
read_handler: &mut dyn FnMut() -> String,
) -> A {
match prog {
ConsoleProg::Done(a) => a,
ConsoleProg::Step(effect, k) => match effect {
ConsoleEffect::Print(msg) => {
print_handler(&msg);
Self::run(k(String::new()), print_handler, read_handler)
}
ConsoleEffect::Read => {
let line = read_handler();
Self::run(k(line), print_handler, read_handler)
}
},
}
}
}
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct TypeConstructorFunctor {
pub name: String,
pub fmap_type: String,
pub laws: Vec<String>,
}
#[allow(dead_code)]
impl TypeConstructorFunctor {
pub fn list() -> Self {
Self {
name: "List".to_string(),
fmap_type: "(a -> b) -> List a -> List b".to_string(),
laws: vec![
"fmap id = id".to_string(),
"fmap (f . g) = fmap f . fmap g".to_string(),
],
}
}
pub fn maybe() -> Self {
Self {
name: "Maybe".to_string(),
fmap_type: "(a -> b) -> Maybe a -> Maybe b".to_string(),
laws: vec![
"fmap id = id".to_string(),
"fmap (f . g) = fmap f . fmap g".to_string(),
],
}
}
pub fn num_laws(&self) -> usize {
self.laws.len()
}
}
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct ProfunctorData {
pub profunctor_name: String,
pub dimap_type: String,
pub is_cartesian: bool,
pub is_cocartesian: bool,
pub is_closed: bool,
}
#[allow(dead_code)]
impl ProfunctorData {
pub fn function_profunctor() -> Self {
ProfunctorData {
profunctor_name: "(->)".to_string(),
dimap_type: "(a -> b) -> (c -> d) -> (b -> c) -> (a -> d)".to_string(),
is_cartesian: true,
is_cocartesian: true,
is_closed: true,
}
}
pub fn star_profunctor(functor: &str) -> Self {
ProfunctorData {
profunctor_name: format!("Star {}", functor),
dimap_type: format!(
"(a -> b) -> (c -> d) -> (b -> {} c) -> (a -> {} d)",
functor, functor
),
is_cartesian: true,
is_cocartesian: false,
is_closed: false,
}
}
pub fn optic_encoding(&self) -> String {
"Profunctor optics: Lens = ∀p. Cartesian p => p a b -> p s t".to_string()
}
pub fn tambara_module_connection(&self) -> String {
"Tambara module: profunctor P with strength α: P a b -> P (c,a) (c,b)".to_string()
}
pub fn bartosz_milewski_connection(&self) -> String {
"Milewski: profunctors and optics in category theory for programmers".to_string()
}
}
pub struct Singleton<T> {
pub value: T,
}
impl<T: Clone> Singleton<T> {
pub fn new(value: T) -> Self {
Self { value }
}
pub fn extract(&self) -> T {
self.value.clone()
}
}
pub struct Arrow<A, B> {
run: Box<dyn Fn(A) -> B>,
}
impl<A: 'static, B: 'static> Arrow<A, B> {
pub fn arr(f: impl Fn(A) -> B + 'static) -> Self {
Self { run: Box::new(f) }
}
pub fn apply(&self, a: A) -> B {
(self.run)(a)
}
pub fn compose<C: 'static>(self, other: Arrow<B, C>) -> Arrow<A, C> {
Arrow::arr(move |a| other.apply(self.apply(a)))
}
}
pub struct AffineTraversal<S, A> {
preview: Box<dyn Fn(&S) -> Option<A>>,
set: Box<dyn Fn(A, S) -> S>,
}
impl<S: 'static, A: 'static> AffineTraversal<S, A> {
pub fn new(
preview: impl Fn(&S) -> Option<A> + 'static,
set: impl Fn(A, S) -> S + 'static,
) -> Self {
Self {
preview: Box::new(preview),
set: Box::new(set),
}
}
pub fn preview(&self, s: &S) -> Option<A> {
(self.preview)(s)
}
pub fn set(&self, a: A, s: S) -> S {
(self.set)(a, s)
}
}
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct WriterMonad<A: Clone> {
pub value: A,
pub log: Vec<String>,
}
#[allow(dead_code)]
impl<A: Clone> WriterMonad<A> {
pub fn new(value: A) -> Self {
Self {
value,
log: Vec::new(),
}
}
pub fn tell(mut self, msg: String) -> Self {
self.log.push(msg);
self
}
pub fn listen(&self) -> (&A, &Vec<String>) {
(&self.value, &self.log)
}
pub fn pass<F: Fn(&Vec<String>) -> Vec<String>>(mut self, f: F) -> Self {
self.log = f(&self.log);
self
}
}
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct ApplicativeData {
pub functor_name: String,
pub pure_type: String,
pub ap_type: String,
pub is_monad: bool,
}
#[allow(dead_code)]
impl ApplicativeData {
pub fn new(name: &str, pure_ty: &str, ap_ty: &str, monad: bool) -> Self {
ApplicativeData {
functor_name: name.to_string(),
pure_type: pure_ty.to_string(),
ap_type: ap_ty.to_string(),
is_monad: monad,
}
}
pub fn maybe_applicative() -> Self {
ApplicativeData {
functor_name: "Maybe".to_string(),
pure_type: "a -> Maybe a".to_string(),
ap_type: "Maybe (a -> b) -> Maybe a -> Maybe b".to_string(),
is_monad: true,
}
}
pub fn validation_applicative() -> Self {
ApplicativeData {
functor_name: "Validation e".to_string(),
pure_type: "a -> Validation e a".to_string(),
ap_type: "Validation e (a -> b) -> Validation e a -> Validation e b".to_string(),
is_monad: false,
}
}
pub fn laws(&self) -> Vec<String> {
vec![
"Identity: pure id <*> v = v".to_string(),
"Composition: pure (.) <*> u <*> v <*> w = u <*> (v <*> w)".to_string(),
"Homomorphism: pure f <*> pure x = pure (f x)".to_string(),
"Interchange: u <*> pure y = pure ($ y) <*> u".to_string(),
]
}
pub fn mcbride_paterson_paper(&self) -> String {
"McBride-Paterson (2008): Applicative programming with effects".to_string()
}
}