Skip to content

Instantly share code, notes, and snippets.

@Thorium
Created April 19, 2012 17:21
Show Gist options
  • Save Thorium/2422428 to your computer and use it in GitHub Desktop.
Save Thorium/2422428 to your computer and use it in GitHub Desktop.
Computational expressions / monad / builder example: Nullable
module BuilderExample
open System
//Example: nullable { ... } with combining functionality
type NullableBuilder() =
let hasValue (a:Nullable<'a>) = a.HasValue
member t.Return(x) = Nullable(x)
member t.Bind(x, rest) =
match hasValue x with
| false -> System.Nullable() //.NET null object
| true -> rest(x.Value)
let nullable = NullableBuilder()
let test =
nullable{
let! a = System.Nullable(3) //"let!" calls builders Bind
let! b = System.Nullable(5) //"let!" calls builders Bind
//Inside computation expression(/monad): easy programming without Nullable-worries:
let mult = a * b
let sum = mult + 1
return sum //"return" calls builders Return(x)
}
//val test : Nullable<int> = 16
//------------------------------------------------------------------------------
// using e.g.
// let! b = System.Nullable()
// would cause to return:
// val test : System.Nullable()
// own { ...} syntax is made with implementing Builder-class
// and (some of) the "interface" members
//------------------------------------------------
// Further reading:
// "Interface" described in: http://msdn.microsoft.com/en-us/library/dd233182.aspx
// More info: http://blogs.msdn.com/b/dsyme/archive/2007/09/22/some-details-on-f-computation-expressions-aka-monadic-or-workflow-syntax.aspx
// Check also Reactive Extensions 2.0 with F# observe { ... }:
// https://github.com/panesofglass/FSharp.Reactive/blob/master/src/Observable.fs
// and: http://fssnip.net/tags/computation+builder and http://fssnip.net/tags/monad
// The same in C-Sharp.
using System;
namespace NullableExtensionMonad
{
/// <summary>
/// This is not so much useful class as it is LINQ-demo.
/// </summary>
static class NullableWrapperExtensions
{
public static TOut? Select<TIn, TOut>(this TIn? source, Func<TIn, TOut> selector)
where TIn: struct where TOut : struct
{
return source.HasValue ? selector(source.Value) : new TOut?();
}
public static TOut? SelectMany<TIn, TIn2, TOut>(this TIn? source, Func<TIn, TIn2?> valueSelector, Func<TIn, TIn2, TOut> resultSelector)
where TIn : struct where TIn2 : struct where TOut : struct
{
var newVal = source.HasValue ? valueSelector(source.Value) : new TIn2?();
return source.HasValue && newVal.HasValue ? resultSelector(source.Value, newVal.Value) : new TOut?();
}
}
class Program
{
static void Main(string[] args)
{
var res1 = from a in (int?)3
from b in (int?)5
select a * b + 5;
Console.WriteLine("First has value: {0}, the first is : {1}", res1.HasValue, res1);
var res2 = from a in (int?)null
from b in (int?)5
select a + b + 5;
Console.WriteLine("Second has value: {0}, the second is : {1}", res2.HasValue, res2);
Console.ReadLine();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment