Есть ли общий способ разложить свободную комонаду по монаде сбоя в "поток значений и окончательную ошибку"?

Cofree comonad полезен для итерации частичных функций способом, который полиморфен для типа ошибки. это coiter походит forM -переключение в монаде ошибок, но она собирает полученные значения в чистом / ленивом виде, и вы видите только ошибку в конце, вниз в структуре данных.

Например, 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

но это кажется немного хакерским. Есть ли лучшее решение?

1 ответ

Я думаю, что это плохое преобразование для больших потоков, потому что вы можете иметь утечку пространства из-за лени. Но для небольших потоков это может быть полезным.

Мы можем разделить это преобразование на две части:

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)
Другие вопросы по тегам