> {-# 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
一般に、任意の Functorに変換でき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
s によるため、この合計になります。) 二重に、帰納型を取り、その最上位の Functor レイヤーを明らかにする をO(n^2)
定義できます。cowrap
> 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)
であり、2 番目の変換のO(n)
合計は になりO(n) + O(n) = O(n)
ます))、それなしで可能かどうかを確認したいと思います。
直接的または間接的に再帰を使用していないことconvert
に注意してください。convert'
気の利いたですね!