【问题标题】:Monadic Programming in C#C# 中的一元编程
【发布时间】:2013-04-21 16:47:07
【问题描述】:

在 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 中列表上的 &gt;&gt;= 和 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# linq haskell functional-programming monads


【解决方案1】:

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

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

【讨论】:

  • 哈,没错。将其更改为new List&lt;List&lt;A&gt;&gt; {new List&lt;A&gt;()},这改变了问题(现在输出不同)但没有解决它,因为输出仍然不正确。感谢您指出这一点。
  • 对!奇迹般有效!谢谢!
【解决方案2】:

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

【讨论】:

    猜你喜欢
    • 2013-10-07
    • 2011-11-10
    • 2012-07-12
    • 2017-04-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-21
    相关资源
    最近更新 更多