简体   繁体   English

C#中的Monadic编程

[英]Monadic Programming in C#

In Haskell, we have the filterM function. 在Haskell中,我们有filterM函数。 The source code for it is: 它的源代码是:

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)

Translating from do notation: 从符号转换:

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)

To the best of my understanding, >>= on lists in Haskell and SelectMany on IEnumerable in C# are the same operation and so, this code should work just fine: 据我所知, >>= on Haskell中的列表和C#中IEnumerable上的SelectMany是相同的操作,因此,这段代码应该可以正常工作:

    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;
                            }
                        }))
                };
        }
    }

But it doesn't work. 但它不起作用。 Can anyone point me to what's wrong here? 谁能指出我这里有什么问题?

My C# is a bit rusty, but it looks like your base case is wrong. 我的C#有点生疏,但看起来你的基本情况是错误的。 You're returning the equivalent of [] (an empty list) while the Haskell version returns [[]] (a list containing an empty list). 当Haskell版本返回[[]] (包含空列表的列表)时,您将返回等效的[] (空列表)。

Your recursive case has the same problem. 你的递归案例有同样的问题。 For example, in the else branch the Haskell version returns [ys] while your version returns ys . 例如,在else分支中,Haskell版本返回[ys]而您的版本返回ys Remember that return in the list monad makes a single element list and has nothing to do with the return keyword in C#. 请记住,列表monad中的return会生成单个元素列表,而与C#中的return关键字无关。

It looks like your C# code is equivalent to: 看起来您的C#代码相当于:

filterM          :: (a -> [Bool]) -> [a] -> [[a]]
filterM _ []     =  return []
filterM p (x:xs) = 
  return $
    p x >>= \flg -> 
    filterM p xs >>= \ys -> 
    if flg then x:ys else ys

Ie return is in the wrong spot. return错误的地方。

I would expect something like this: 我希望这样的事情:

        return predicate(x).SelectMany(flg => 
            xs.WhereM(predicate).SelectMany(ys =>
                new List<IEnumerable<A>> { flg ? (new List<A> {x}).Concat(ys) : ys }))

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM