Cofree
comonad对于以错误类型的多态方式迭代部分函数非常有用。它的coiter
类似于forM
- 在一个错误monad中循环,但它以纯/懒的方式收集生成的值,你只在数据结构中向下看到一个错误。
例如,Cofree Identity
(不允许失败!)是无限流,而Cofree Maybe
与NonEmpty
同构,而Cofree (Either e) a
基本上是(NonEmpty a, e)
(成功迭代值列表加上最后发生的错误)。
现在我想知道在单个错误monad上没有特定模式匹配的情况下,评估结果的最佳方法是什么。由于Foldable
实例(例如toList
),提取所有值非常容易,但我不确定如何最好地掌握错误< / em>的。有可能利用Foldable
来获取值的 rid 并留下错误部分:
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
但这感觉有点hackish。有更好的解决方案吗?
答案 0 :(得分: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)