[英]Monadic Programming in C#
在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)
從符號轉換:
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)
據我所知, >>=
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;
}
}))
};
}
}
但它不起作用。 誰能指出我這里有什么問題?
我的C#有點生疏,但看起來你的基本情況是錯誤的。 當Haskell版本返回[[]]
(包含空列表的列表)時,您將返回等效的[]
(空列表)。
你的遞歸案例有同樣的問題。 例如,在else
分支中,Haskell版本返回[ys]
而您的版本返回ys
。 請記住,列表monad中的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 }))
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.