/* * 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()))); }
public static Gen <float> ToFloat(this Gen <double> gen) { return(gen.Bind(x => ((float)x).ToGen())); }
public static Gen <long> ToLong(this Gen <int> gen) { return(gen.Bind(x => ((long)x).ToGen())); }
/* ## 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())); }
/* * 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())); }
/// <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()))); }