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#有点生疏,但看起来你的基本情况是错误的。你返回相当于[]
(一个空列表),而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 }))