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 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
// Copyright 2016 Pierre Talbot (IRCAM) // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your // option. This file may not be copied, modified, or distributed // except according to those terms. //! We distinguish between ground and non-ground types. A ground type is basically a type that is not parametrized by a type parameter. This distinction is done for implementing binary operations on types. //! //! Let's start with an example implementing `Add` for an option-like type with the following semantics: //! //! * `Some(x) + Some(y) = Some(x + y)` //! * `Some(x) + None = None` //! * `None + Some(y) = None` //! * `None + None = None` //! //! As we can see, we require inner values to be addable too. There is also another use-case: //! //! * `Some(x) + y = Some(x + y)` //! * `x + Some(y) = Some(x + y)` //! * `None + y = None` //! * `x + None = None` //! //! So far we have three overloadings of `Add` for `Option`: //! //! * `impl<T, U> Add<Option<T>> for Option<U>` //! * `impl<T, U> Add<T> for Option<U>` //! * `impl<T, U> Add<Option<T>> for U` //! //! There is several problems: //! //! * Generally, implementing `impl<T, U> Add<Option<T>> for U` will lead to the compilation error: "only traits defined in the current crate can be implemented for a type parameter" or "type parameter `U` must be used as the type parameter for some local type". //! * Also, admit that we define `Add` for a type `Vec<T>` in a similar fashion, we will have a conflicting implementation in case we do `Option<A> + Vec<B>`. First of all, saying we want to define such a computation, what should be the type of the result? `Vec<Option<C>>` or `Option<Vec<C>>` (`C` being `<A as Add<B>>::Output`)? A wrong solution is to depend on the operation order, so `a + b` and `b + a` would be different, which violates the commutativity property of addition. Our choice here is to let undefined such implementation and only propose one between `Option<A>` and `Option<B>`, and between `Option<A>` and `B` if `B` is a ground type (implements `GroundType`). //! //! ```rust //! use gcollections::kind::*; //! use std::ops::Add; //! //! struct Maybe<T> { //! value: Option<T> //! } //! //! impl<T> Maybe<T> { //! fn some(value: T) -> Maybe<T> { //! Maybe { //! value: Some(value) //! } //! } //! fn none() -> Maybe<T> { //! Maybe { //! value: None //! } //! } //! } //! //! impl<T, U, R> Add<Maybe<T>> for Maybe<U> where //! U: Add<T, Output=R> //! { //! type Output = Maybe<R>; //! //! fn add(self, rhs: Maybe<T>) -> Self::Output { //! if let Some(x) = self.value { //! if let Some(y) = rhs.value { //! return Maybe::some(x + y); //! } //! } //! Maybe::none() //! } //! } //! //! impl<T, U, R> Add<T> for Maybe<U> where //! U: Add<T, Output=R>, //! T: GroundType //! { //! type Output = Maybe<R>; //! //! fn add(self, rhs: T) -> Self::Output { //! match self.value { //! Some(x) => Maybe::some(x + rhs), //! None => Maybe::none() //! } //! } //! } //! //! impl<T,R> Add<Maybe<T>> for u32 where //! T: Add<u32, Output=R> //! { //! type Output = Maybe<R>; //! fn add(self, rhs: Maybe<T>) -> Self::Output { //! rhs + self //! } //! } //! ``` //! //! The last implementation is for `A + Option<B>`. It should be done at the ground type level but for doing it in a generic manner, we would need all non-ground types to implement a trait such as `Monad`. Thus it would be possible to propose a generic implementation handling the commutativity property of addition. However, higher-order types are not available in Rust yet so we implement `A + Option<B>` in the optional module where the ground types `A` are fixed and defined (here just shown for `u32`). //! //! pub trait GroundType {} pub trait Collection { type Item; } pub trait AssociativeCollection : Collection { type Location; } pub trait IntervalKind {} pub trait SequenceKind {}