6

Cofreecomonad は、エラー型で多態的な方法で部分関数を反復するのに役立ちます。これはエラー モナドでのループに似ていますが、生成された値を純粋/遅延的な方法で収集し、データ構造体の最後にエラーが表示されるだけですcoiterforM

たとえば、Cofree Identity(失敗は許可されません!) は無限ストリームですが、Cofree Maybeは と同形NonEmptyであり、Cofree (Either e) a基本的には(NonEmpty a, e)(成功した反復値のリストと最後に発生するエラー) です。

ここで、単一のエラーモナドで特定のパターンマッチングを行わずに、結果を評価する最良の方法は何だろうと考えています。インスタンスのおかげですべてのを抽出するのは非常に簡単ですがFoldable(例: )、エラーtoListを取得する最善の方法がわかりません。それを悪用して、値を取り除き、エラー部分を残すことができます。Foldable

vals'n'err :: (Monad m, Foldable m)
          => Cofree m a -> (NonEmpty a, (m ()))
vals'n'err (a :< q) = case toList q of
        [] -> (a:|[], const () <$> q)
        l  -> first (pure a<>)
           $ foldr1 (\(bs,e) (cs,f) -> (bs<>cs, e>>f)) $ vals'n'err<$>l

しかし、これは少しハックな気がします。より良い解決策はありますか?

4

1 に答える 1

4

遅延によってスペースリークが発生する可能性があるため、大きなストリームの変換は悪いと思います。ただし、小さなストリームの場合は使用できる場合があります。

この変換を 2 つに分けることができます。

vals :: Foldable f => Cofree f a -> NonEmpty a
vals = NonEmpty.fromList . Foldable.toList

err :: Monad m => Cofree m a -> m b
err (_ :< m) = m >>= err

そして、一緒に結合します:

vals'n'err :: (Monad m, Foldable m) => Cofree m a -> (NonEmpty a, m b)
vals'n'err w = (vals w, err w)
于 2016-12-22T15:17:21.950 に答える