예제 #1
0
 /*
  * The `SelectMany` operation is called _flatMap_ in some functional
  * languages. It performs a double `Bind` as it combines a generator for
  * `T`'s and a generator for `U`'s, and maps them to a generator for `V`'s.
  * Whenever we have more than one select clause in a LINQ expression this
  * method is called.
  */
 public static Gen <V> SelectMany <T, U, V> (this Gen <T> gen,
                                             Func <T, Gen <U> > project, Func <T, U, V> select)
 {
     /*
      * As for `Select` the correct implementation reveals itself by
      * following the types. Note that the types force us to arrange
      * the `Bind` operations in a specific order.
      */
     return(gen.Bind(a => project(a).Bind(b => select(a, b).ToGen())));
 }
예제 #2
0
 public static Gen <float> ToFloat(this Gen <double> gen)
 {
     return(gen.Bind(x => ((float)x).ToGen()));
 }
예제 #3
0
 public static Gen <long> ToLong(this Gen <int> gen)
 {
     return(gen.Bind(x => ((long)x).ToGen()));
 }
예제 #4
0
 /*
 ## Converting Generators
 ## We need also to do type conversions between the generators. The
 ## following methods are defined mostly for convenience, to avoid
 ## boilerplate code when constructing generators.
 */
 public static Gen <U> Cast <T, U> (this Gen <T> gen) where T : U
 {
     return(gen.Bind(x => ((U)x).ToGen()));
 }
예제 #5
0
 /*
  * Note that the process was almost mechanical. Think for a while, if you
  * could implement the method differently. You will notice that if you try
  * to change the implementation in any way, the code will not compile
  * anymore; the types do not match.
  *
  * This is the reason, why we usually do not have to concern ourselves
  * with the monad laws. If your monad type is a pure function, it is
  * impossible to define the _return_ and _bind_ operation in a way that
  * violates the monad laws. There is literally only one way to implement
  * them. Be warned that this realization can easily blow your mind...
  *
  ### What Have We Achieved?
  ###Before going further, let's step back and contemplate what we just
  ###implemented. We defined two operations: `ToGen` converts a value into
  ###a generator, and `Bind` turns a generator for `T`'s into generator for
  ###`U`'s when given a function that maps a value of type `T` to a
  ###generator of type `Gen<U>`.
  ###
  ###Essentially we defined a way to create generators and chain them
  ###together while hiding the two parameters of the `Gen<T>` delegate.
  ###This does not sound like a big deal, but it is.
  ###
  ###We can construct arbitrary complex generators and implement almost
  ###all the functionality we need using just these two operations. The
  ###instance of the Random class and the size parameter are passed along
  ###transparently in the background. This simplifies our code and makes it
  ###_composable_. With monads we achieve true code reusability.
  ###
  ## Relation to LINQ
  ##In the introduction there was a vague claim that LINQ and monads are
  ##somehow related. Now we will show exactly how. We will implement LINQ's
  ##core operations `Select` and `SelectMany` using `ToGen` and `Bind`. The
  ##`Select*` methods enable the syntactic sugaring that allows us to write
  ##generators as LINQ expressions.
  ##
  ##When C# compiler is desugaring a LINQ expression, it just rewrites it
  ##using the `Select` and `SelectMany`	extension methods. If these methods
  ##are defined somewhere and they have the correct signature, then the
  ##compiler will be happy.
  ##
  ##The trick is thus to define those methods for our own monad type, and
  ##we get a [domain specific language](https://en.wikipedia.org/wiki/Domain-specific_language)
  ##for our generators. This DSL just happens to have the same syntax as
  ##LINQ. Haskell provides
  ##[syntactic sugaring](https://en.wikibooks.org/wiki/Haskell/do_notation)
  ##for monads too, although its syntax resembles an imperative program
  ##rather than a SQL query. Nevertheless, the idea is exactly the same.
  ##
  ### Implementing Select and SelectMany
  ###
  ###The signature of the LINQ's `Select` method is almost the same as for
  ###`Bind`. The only difference is the type of the function given as the
  ###second argument. Instead of `Func<T, Gen<U>>` it is `Func<T, U>`.
  ###Converting the function type to one expected by `Bind` is trivial using
  ###`ToGen`.
  */
 public static Gen <U> Select <T, U> (this Gen <T> gen, Func <T, U> select)
 {
     return(gen.Bind(a => select(a).ToGen()));
 }
예제 #6
0
파일: Gen.cs 프로젝트: johtela/Compose3D
 /// <summary>
 /// SelectMany extension method needed to enable Linq's syntactic sugaring.
 /// </summary>
 public static Gen <V> SelectMany <T, U, V> (this Gen <T> gen,
                                             Func <T, Gen <U> > project, Func <T, U, V> select)
 {
     return(gen.Bind(a => project(a).Bind(b => select(a, b).ToGen())));
 }