7

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 の on リストとSelectManyC IEnumerable# の on リストは同じ操作なので、このコードは問題なく動作するはずです。

    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;
                            }
                        }))
                };
        }
    }

しかし、うまくいきません。誰かがここで何が悪いのか教えてもらえますか?

4

2 に答える 2

4

私の C# は少しさびていますが、ベース ケースが間違っているようです。[]Haskell バージョンが[[]](空のリストを含むリスト) を返すのに対し、(空のリスト)と同等のものを返しています。

あなたの再帰的なケースにも同じ問題があります。たとえば、elseブランチでは、Haskell バージョンが返さ[ys]れますが、バージョンは が返されますys。リストのモナドは単一の要素リストを作成し、C#returnのキーワードとは何の関係もないことに注意してください。return

于 2013-04-27T16:54:10.883 に答える
1

あなたの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-04-27T17:12:51.773 に答える