Как эффективно преобразовать индуктивный тип в коиндуктивный тип (без рекурсии)?

> {-# LANGUAGE DeriveFunctor, Rank2Types, ExistentialQuantification #-}

Любой индуктивный тип определяется так

> newtype Ind f = Ind {flipinduct :: forall r. (f r -> r) -> r}
> induction = flip flipinduct

induction имеет тип (f a -> a) -> Ind f -> a, Существует двойное понятие, называемое коиндукция.

> data CoInd f = forall r. Coinduction (r -> f r) r
> coinduction = Coinduction

coinduction имеет тип (a -> f a) -> a -> CoInd f, Обратите внимание, как induction а также coinduction являются двойственными. В качестве примера индуктивных и коиндуктивных типов данных рассмотрим этот функтор.

> data StringF rec = Nil | Cons Char rec deriving Functor

Без рекурсии, Ind StringF является конечной строкой и CoInd StringF является конечной или бесконечной строкой (если мы используем рекурсию, они обе являются конечными или бесконечными или неопределенными строками). В общем, можно конвертировать Ind f -> CoInd f для любого функтора f, Например, мы можем обернуть значение функтора в коиндуктивный тип

> wrap :: (Functor f) => f (CoInd f) -> CoInd f
> wrap fc = coinduction igo Nothing where
>   --igo :: Maybe (CoInd f) -> f (Maybe (CoInd f))
>   igo Nothing  = fmap Just fc
>   igo (Just (Coinduction step seed)) = fmap (Just . Coinduction step) $ step seed

Эта операция добавляет дополнительную операцию (сопоставление с образцом Maybe) за каждый шаг. Это означает, что это дает O(n) накладные расходы.

Мы можем использовать индукцию на Ind f а также wrap получить CoInd f,

> convert :: (Functor f) => Ind f -> CoInd f
> convert = induction wrap

Это O(n^2), (Получение первого слоя O(1), но n-й элемент O(n) из-за вложенного Maybe с, делая это O(n^2) итого.) Вдвойне мы можем определить cowrap, который принимает индуктивный тип и раскрывает свой верхний слой Functor.

> cowrap :: (Functor f) => Ind f -> f (Ind f)
> cowrap = induction igo where
>    --igo :: f (f (Ind f)) -> f (Ind f)
>    igo = fmap (\fInd -> Ind $ \fold -> fold $ fmap (`flipinduct` fold) fInd)

induction всегда O(n) так же cowrap,

Мы можем использовать coinduction производить CoInd f от cowrap а также Ind f,

> convert' :: (Functor f) => Ind f -> CoInd f
> convert' = coinduction cowrap

Это опять O(n) каждый раз, когда мы получаем элемент, в общей сложности O(n^2),


Мой вопрос, без использования рекурсии (прямо или косвенно), можем ли мы конвертировать Ind f в CoInd f в O(n) время?

Я знаю как это сделать с помощью рекурсии (конвертировать Ind f в Fix f а потом Fix f в CoInd f (первоначальное преобразование O(n), но тогда каждый элемент из CoInd f является O(1), делая второе преобразование O(n) всего и O(n) + O(n) = O(n))), но я хотел бы увидеть, если это возможно без.

Соблюдайте это convert а также convert' никогда не использовал рекурсию, прямо или косвенно. Отлично, не так ли?

1 ответ

Да, это формально возможно:

https://github.com/jyp/ControlledFusion/blob/master/Control/FixPoints.hs

Однако преобразование все еще требует создания промежуточного буфера, который может быть выполнен только с использованием цикла, во время выполнения.

Причина, лежащая в основе этого ограничения, заключается в том, что значение "индуктивного" типа отвечает заданному порядку оценки (*), в то время как значение "коиндуктивного" типа фиксирует порядок оценки. Единственный способ сделать возможным переход без принудительного повторного вычисления - это выделить какой-то промежуточный буфер для запоминания промежуточных результатов.

Кстати, преобразование из "коиндуктивного" в "индуктивное" не требует буфера, но требует пересчета порядка оценки с помощью явного цикла.

Кстати, я изучил основные концепции в двух статьях: 1. В Haskell для эффективных потоков: https://gist.github.com/jyp/fadd6e8a2a0aa98ae94d2. В классической линейной логике - для массивов и потоков. http://lopezjuan.com/limestone/vectorcomp.pdf

(*) Это предполагает строгий язык. Ситуация немного меняется при ленивой оценке, но концепции и окончательный ответ совпадают. Есть несколько комментариев о ленивой оценке в исходном коде.

Другие вопросы по тегам