Skip to content

Instantly share code, notes, and snippets.

@lanwin
Created March 3, 2011 15:06
Show Gist options
  • Save lanwin/852890 to your computer and use it in GitHub Desktop.
Save lanwin/852890 to your computer and use it in GitHub Desktop.
Simply object extension with provides an maybe monad.
public static class ObjectExtensions
{
public static IEnumerable<T> ToMaybe<T>(this T obj)
{
return Equals(obj,null) ? Enumerable.Empty<T>() : new[] {obj};
}
}
@forki
Copy link

forki commented Mar 3, 2011

I would split this into two "constructors":

public class Maybe
{
    public static IEnumerable<T> Some<T>(T element)
    {
        return new[] {element};
    }

    public static IEnumerable<T> None<T>(){ return Enumerable.Empty<T>();    } 
}

@lanwin
Copy link
Author

lanwin commented Mar 3, 2011

The problem is this would not solve my use case. I want to use it this way:

ReturnsAStringOrNull()
  .ToMaybe()
  .Run(v=>Print(v));

@lanwin
Copy link
Author

lanwin commented Mar 3, 2011

This way i can avoid unnecessary null checks.

@forki
Copy link

forki commented Mar 4, 2011

Ah I see. But in an ideal world you would have ReturnsMaybeAString() which would already return the IEnumerable and would use the methods above.

@ilkerde
Copy link

ilkerde commented Mar 4, 2011

@lanwin this is perfectly valid, imho. you did the "unit" part (or must is say function?!?) of the monad. the "bind" part is still missing, although it could be easily applied by means of linq - or your Run() method.

A note aside: Enumberable even provides the singleton list for you: Enumerable.Repeat(t, 1);

@lanwin
Copy link
Author

lanwin commented Mar 4, 2011

The Run method is part of RX and enumerates the enumerable and optionally allows you to pass a side effect to it.

RX also have a EnumerableEx.Return(t). Please have a look at the System.CoreEx assembly of RX which provides a lot useful additions to IEnumerable.

I am not very happy with the naming of my extension method. More correct would be ToEnumerable or AsEnumerable. But the framework has both of them already so i would have collisions.

@ilkerde
Copy link

ilkerde commented Mar 4, 2011

@lanwin nice. one more reason have a look at RX. The Run() seems to me as if it resembles to the "do" of Haskell. Despite, it would finally render the gazillions of custom ForEach() extensions useless ;)

@lanwin
Copy link
Author

lanwin commented Mar 4, 2011

Hmm as i said it is no 100% like foreach. On first it made no sens that there is an Run() without parameters. But that only run thru the enumerable without accessing the result.

They also provide a Do. But that allows you to add a side effect while enumerating the enumerable. But its dose not start the enumeration. Example:

GetList()
.Where(item=="foo")
.Do(item=>Console.WriteLine(item))
.Run();

@forki
Copy link

forki commented Mar 4, 2011

lanwin is right. Since IEnumerable is lazy you need something which starts the process. Foreach() will do so but breaks the monad. Do() is something which stays in the monad and therefor keeps laziness.

@ilkerde
Copy link

ilkerde commented Mar 4, 2011

A slight, but noteworthy difference. I don't know RX, so bare with me. I assumed that RX's Run() is the same as you have used it in your comment - which for me is a simple application like a commonly used ForEach-Extension does.

I wasn't aware of that "do" adds side effects without application. This fact actually is a clear indicator that i yet have a long learning path before me.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment