C#中的Monadic编程

Mic*_*ael 7 c# linq monads haskell functional-programming

在Haskell中,我们有这个filterM功能.它的源代码是:

filterM          :: (Monad m) => (a -> m Bool) -> [a] -> m [a]
filterM _ []     =  return []
filterM p (x:xs) =  do
flg <- p x
ys  <- filterM p xs
return (if flg then x:ys else ys)
Run Code Online (Sandbox Code Playgroud)

从符号转换:

filterM          :: (Monad m) => (a -> m Bool) -> [a] -> m [a]
filterM _ []     =  return []
filterM p (x:xs) =  p x >>= \flg -> 
                    filterM p xs >>= \ys -> 
                    return(if flg then x:ys else ys)
Run Code Online (Sandbox Code Playgroud)

尽我的理解,>>=在Haskell的列表和SelectManyIEnumerableC#中是相同的操作,因此,这段代码应该只是罚款:

    public static IEnumerable<IEnumerable<A>> WhereM<A>(this IEnumerable<A> list, Func<A, IEnumerable<bool>> predicate)
    {
        // Like Haskells null
        if (list.Null())
        {
            return new List<List<A>> {new List<A>()};
        }
        else
        {
            var x = list.First();
            var xs = list.Tail(); // Like Haskells tail

            return new List<IEnumerable<A>>
                {
                    predicate(x).SelectMany(flg => xs.WhereM(predicate).SelectMany(ys =>
                        {
                            if (flg)
                            {
                                return (new List<A> {x}).Concat(ys);
                            }
                            else
                            {
                                return ys;
                            }
                        }))
                };
        }
    }
Run Code Online (Sandbox Code Playgroud)

但它不起作用.谁能指出我这里有什么问题?

ham*_*mar 4

我的 C# 有点生疏,但看起来你的基本情况是错误的。[]当 Haskell 版本返回(包含空列表的列表)时,您返回的是[[]](一个空列表)的等价物。

你的递归案例也有同样的问题。例如,在else分支中 Haskell 版本返回[ys],而您的版本返回ys。请记住,return列表 monad 生成单个元素列表,与 C# 中的关键字无关return