在 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# 有点生疏,但看起来你的基本情况是错误的。您返回的是 []
的等效项(空列表),而 Haskell 版本返回的是 [[]]
(包含空列表的列表)。
你的递归案例有同样的问题。例如,在 else
分支中,Haskell 版本返回 [ys]
而您的版本返回 ys
。请记住,列表 monad 中的 return
构成单个元素列表,与 C# 中的 return
关键字无关。
关于c# - C# 中的 Monadic 编程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16254592/