2011-09-22 10 views
7

Sto provando a scrivere una semplice monad Maybe in C#. Voglio essere in grado di utilizzare la sintassi della query LINQ con esso. Questo è quello che sono venuto in mente finora:Uso della sintassi di query LINQ con personalizzato Forse implementazione di monad

using System; 
using System.Collections.Generic; 

abstract class Maybe<A> { 
    public abstract Maybe<B> SelectMany<B>(Func<A, Maybe<B>> f); 
    public abstract Maybe<B> Select<B>(Func<A, B> f); 
} 

class Just<A> : Maybe<A> { 
    private readonly A a; 

    public Just(A a) { 
    this.a = a; 
    } 

    override public Maybe<B> SelectMany<B>(Func<A, Maybe<B>> f) { 
    return f(a); 
    } 

    override public Maybe<B> Select<B>(Func<A, B> f) { 
    return new Just<B>(f(a)); 
    } 

    override public string ToString() { 
    return "Just " + a; 
    } 
} 

class Nothing<A> : Maybe<A> { 
    override public Maybe<B> SelectMany<B>(Func<A, Maybe<B>> f) { 
    return new Nothing<B>(); 
    } 

    override public Maybe<B> Select<B>(Func<A, B> f) { 
    return new Nothing<B>(); 
    } 

    override public string ToString() { 
    return "Nothing"; 
    } 
} 

static class Program { 
    public static void Main(string[] args) { 
    Maybe<int> m = new Just<int>(12); 
    Maybe<int> n = new Nothing<int>(); 
    Maybe<int> result = from m0 in m 
         from n0 in n 
         select m0 + n0; 
    Console.WriteLine(result); 
    } 
} 

E questo è il messaggio di errore:

prog.cs(48,25): error CS1501: No overload for method `SelectMany' takes `2' arguments 
prog.cs(5,28): (Location of the symbol related to previous error) 
Compilation failed: 1 error(s), 0 warnings 

Qualcuno può per favore mi guida su quello che devo fare per essere in grado di utilizzare la sintassi di query con la mia implementazione Maybe? Grazie.

risposta

8

SelectMany must dovrebbe essere dichiarato come estensione in una classe statica, ad esempio:

public static class Maybe { 

    public static Maybe<B> SelectMany<B>(this Maybe<A> maybe, Func<A, Maybe<B>> f) { 
     return f(a); 
    } 

    ... 
} 

EDIT:

hai ancora bisogno di un pezzo. Con questo dovrebbe funzionare:

public static Maybe<V> SelectMany<T, U, V>(this Maybe<T> m, Func<T, Maybe<U>> k, Func<T, U, V> s) 
{ 
    return m.SelectMany(x => k(x).SelectMany(y => new Just<V>(s(x, y)))); 
} 

Hai bisogno di questo perché:

from m0 in m 
from n0 in n 
select m0 + n0 

sarebbe tradotto in:

m.SelectMany(m0 => n, (m, n0) => m0 + n0); 

Invece, ad esempio:

var aa = new List<List<string>>(); 
var bb = from a in aa 
      from b in a 
      select b; 

è tradotto in

aa.SelectMany(a => a); 
+0

[Non credo.] (Http://ideone.com/2dQcN) – missingfaktor

+0

http://blogs.msdn.com/b/wesdyer/archive/2008/01/11/the -marvels-of-monads.aspx – onof

+0

Ho apportato la modifica suggerita. [Ancora non funziona.] (Http://ideone.com/ofMKV) – missingfaktor

Problemi correlati