2016-12-22 18 views
6

Код Cofree comonad полезен для итерации частичных функций способом, который является полиморфным по типу ошибки. Его coiter напоминает forM -looping в monad ошибки, но он собирает полученные значения чистым/ленивым способом, и вы видите только ошибку в конце, вниз в структуре данных.Существует ли общий способ разложения бесплатного comonad над модой отказа в «поток значений и конечную ошибку»?

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

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

+0

От конструктивного POV получать '(NonEmpty а, е)' из 'косвободным (или е) a 'не имеет для меня большого смысла, так как' Cofree' является коиндуктивным типом, и вполне нормально для 'Cofree (или e) a' быть бесконечным потоком, чередующимся« Right's », но вы обещаете всегда верните 'e'. Не удивительно, что «vals'n'err» чувствует себя взломанным. – user3237465

+0

@ user3237465: да. Итак, какую подпись вы предложили бы? – leftaroundabout

+0

Я не вижу здесь проблемы. Потребление «Cofree (или e) a» потоковым способом и остановка на «левом» - это общий и разумный способ пойти, зачем рисковать получить нечеткое утечку дна типа 'e'? – user3237465

ответ

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) 
+0

Да, да. Благодаря! – freestyle

+0

'vals' обязательно должен использовать' foldMap1'. – dfeuer

+0

@dfeuer Возможно, но экземпляр 'Foldable1 (Cofree f)' имеет ограничение 'Foldable1 f'. Это уменьшит набор возможных типов. С другой стороны, я не понимаю такого ограничения, почему бы не «экземпляр Foldable f => Foldable1 (Cofree f)». – freestyle

 Смежные вопросы

  • Нет связанных вопросов^_^