6

comonadCofree对于以错误类型的多态方式迭代部分函数很有用。它coiter类似于forM错误单子中的循环,但它以纯/惰性方式收集生成的值,并且您只会在数据结构的末尾看到错误。

例如,Cofree Identity(no failure allowed!) 是一个无限流,而与 ,Cofree Maybe同构NonEmpty,并且Cofree (Either e) a基本上是(NonEmpty a, e)(成功迭代值的列表加上最后发生的错误)。

现在我想知道评估结果的最佳方法是什么,而不需要对单个错误单子进行特定的模式匹配。由于实例(例如),提取所有非常容易,但我不确定如何最好地掌握错误。可以利用它来摆脱这些值并留下错误部分:FoldabletoListFoldable

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

我认为对于大流来说这是不好的转换,因为你可能会因为懒惰而导致空间泄漏。但对于小流,它可能有用。

我们可以将此转换分为两部分:

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 回答