c#中的一元编程

本文关键字:一元 编程 | 更新日期: 2023-09-27 18:11:04

在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)

翻译自do符号:

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)

据我所知,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;
                            }
                        }))
                };
        }
    }

但是它不起作用。有人能告诉我哪里不对吗?

c#中的一元编程

我的c#有点生疏,但看起来你的基本情况是错误的。你返回相当于[](一个空列表),而Haskell版本返回[[]](一个包含空列表的列表)。

递归情况也有同样的问题。例如,在else分支中,Haskell版本返回[ys],而您的版本返回ys。请记住,列表单子中的return创建了一个单元素列表,与c#中的return关键字无关。

看起来你的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

return放错位置了。

我希望是这样的:

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