1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
/// A comonoid in a monoidal category is a monoid /// in the dual category, what is the problem? /// /// Being the dual to a monoid, it consists of: /// /// - The dual to unit, a function from `T` to `()` called `counit`. /// - The dual to multiplication, a function from `T` to `(T, T)` called `comult`. /// /// It is useful within Rust's ownership type system, /// to represent a type that can be both cloned and destroyed. /// /// There is a trivial implementation of this trait for every /// type that implements `Clone`, as reflected by the `Comonoidal` /// newtype wrapper, with `discard` as `counit`, and `duplicate` as `comult`. /// The behaviour of `counit` and `comult` can be altered by the /// implementation of [`Drop`](http://doc.rust-lang.org/std/ops/trait.Drop.html) /// and [`Clone`](http://doc.rust-lang.org/std/clone/trait.Clone.html), /// respectively. pub trait Comonoid { /// The dual to the monoidal unit. fn counit(self) -> (); /// The dual to the monoidal multiplication. fn comult(self) -> (Self, Self); } /// Takes ownership of a value and returns `()`, /// rendering it unusable. pub fn discard<T>(_: T) -> () {} /// Takes ownership of a value and returns a tuple of /// clones. pub fn duplicate<T>(a: T) -> (T, T) where T: Clone { (a.clone(), a) } /// A newtype wrapper to make a comonoid out of any /// cloneable type. pub struct Comonoidal<T>(T); impl<T> From<T> for Comonoidal<T> { fn from(a: T) -> Comonoidal<T> { Comonoidal(a) } } impl<T> AsRef<T> for Comonoidal<T> { fn as_ref(&self) -> &T { &self.0 } } impl<T> AsMut<T> for Comonoidal<T> { fn as_mut(&mut self) -> &mut T { &mut self.0 } } impl<T> Clone for Comonoidal<T> where T: Clone { fn clone(&self) -> Self { let a = self.0.clone(); Comonoidal(a) } } impl<T> Comonoid for Comonoidal<T> where T: Clone { fn counit(self) -> () { discard(self) } fn comult(self) -> (Self, Self) { duplicate(self) } } #[test] fn test_counit() { let x = from(42); assert_eq!(Comonoid::counit(x), ()); } #[test] fn test_comult() { let x = from(42); let (y, z) = Comonoid::comult(x); assert_eq!(y.0, 42); assert_eq!(z.0, 42); }