use core::marker::PhantomData;
use super::category::Category;
use super::functor::Functor;
pub trait TerminalTarget {
type Category: Category;
fn target() -> <Self::Category as Category>::Object;
}
pub struct TerminalFunctor<Src, T>(PhantomData<(Src, T)>);
impl<Src, T> Functor for TerminalFunctor<Src, T>
where
Src: Category,
T: TerminalTarget,
{
type Source = Src;
type Target = T::Category;
fn map_object(_: &<Src as Category>::Object) -> <T::Category as Category>::Object {
T::target()
}
fn map_morphism(_: &<Src as Category>::Morphism) -> <T::Category as Category>::Morphism {
<T::Category>::identity(&T::target())
}
crate::relationship_meta!(
"TerminalFunctor",
"constant functor collapsing source to a single target aspect",
"Mac Lane (1971) Ch. II §1"
);
}
#[cfg(test)]
mod tests {
use super::*;
use crate::category::laws::assert_functor_laws;
use crate::category::{Arrow, Concept};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
enum Light {
Red,
Green,
}
impl Concept for Light {
fn variants() -> Vec<Self> {
vec![Light::Red, Light::Green]
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
struct LightEdge {
from: Light,
to: Light,
}
impl Arrow for LightEdge {
type Object = Light;
type Kind = ();
fn source(&self) -> Light {
self.from
}
fn target(&self) -> Light {
self.to
}
fn kind(&self) {}
}
struct LightCat;
impl Category for LightCat {
type Object = Light;
type Morphism = LightEdge;
fn identity(obj: &Light) -> LightEdge {
LightEdge {
from: *obj,
to: *obj,
}
}
fn compose(f: &LightEdge, g: &LightEdge) -> Option<LightEdge> {
if f.to != g.from {
return None;
}
Some(LightEdge {
from: f.from,
to: g.to,
})
}
fn morphisms() -> Vec<LightEdge> {
let vs = Light::variants();
vs.iter()
.flat_map(|&a| vs.iter().map(move |&b| LightEdge { from: a, to: b }))
.collect()
}
}
struct RedTarget;
impl TerminalTarget for RedTarget {
type Category = LightCat;
fn target() -> Light {
Light::Red
}
}
type LightToRed = TerminalFunctor<LightCat, RedTarget>;
#[test]
fn terminal_functor_onto_red_satisfies_laws() {
assert_functor_laws::<LightToRed>();
}
}