簡體   English   中英

流媒體包的Stream數據類型是否等同於FreeT?

[英]Is the streaming package's Stream data type equivalent to FreeT?

包定義了Stream類型,如下所示:

data Stream f m r
  = Step !(f (Stream f m r))
 | Effect (m (Stream f m r))
 | Return r

Stream類型的評論說明如下:

Stream數據類型等同於FreeT ,可以表示任何有效的連續步驟,其中步驟或“命令”的形式由第一個(仿函數)參數指定。

我想知道Stream類型如何等同於FreeT

這是FreeT的定義:

data FreeF f a b = Pure a | Free (f b)
newtype FreeT f m a = FreeT { runFreeT :: m (FreeF f a (FreeT f m a)) }

看起來不可能在這兩種類型之間創建同構。

具體來說,我沒有找到一種方法來編寫以下兩個使它們成為同構的函數:

freeTToStream :: FreeT f m a -> Stream f m a
streamToFreeT :: Stream f m a -> FreeT f m a

例如,我不知道如何表達像Return "hello" :: Stream fm String作為FreeT

我想它可以像下面那樣完成,但是Pure "hello"必然會被包裝在m ,而在Return "hello" :: Stream fm String它不是:

FreeT $ pure $ Pure "hello" :: Applicative m => FreeT f m a

可以認為Stream等同於FreeT即使它們之間似乎不可能創建同構嗎?

有一些小的差異使它們在字面上不等同。 特別是, FreeT強制執行fm的交替,

FreeT f m a = m (Either a (f (FreeT f m a) = m (Either a (f (m (...))))
                                          -- m            f  m  -- alternating

Stream允許口吃,例如,我們可以構建以下兩個Effect之間沒有Step

Effect (return (Effect (return (Return r))))

在某種意義上應該是等同的

Return r

因此,我們將通過以下方程取一個Stream的商,這些方程展平了Effect層:

Effect (m >>= \a -> return (Effect (k a))) = Effect (m >>= k)
Effect (return x) = x

在該商下,以下是同構

freeT_stream :: (Functor f, Monad m) => FreeT f m a -> Stream f m a
freeT_stream (FreeT m) = Effect (m >>= \case
  Pure r -> return (Return r)
  Free f -> return (Step (fmap freeT_stream f))

stream_freeT :: (Functor f, Monad m) => Stream f m a -> FreeT f m a
stream_freeT = FreeT . go where
  go = \case
    Step f -> return (Free (fmap stream_freeT f))
    Effect m -> m >>= go
    Return r -> return (Pure r)

注意go循環以展平多個Effect構造函數。


(freeT_stream . stream_freeT) = id(freeT_stream . stream_freeT) = id

我們在流x上進行歸納。 說實話,我是憑空推出誘導假設的。 肯定存在感應不適用的情況。 這取決於mf是什么,並且可能還有一些非常重要的設置以確保這種方法對商類型有意義。 但是在這個方案適用的情況下,仍然應該有許多具體的mf 我希望有一些明確的解釋可以將這種偽覆蓋轉化為有意義的東西。

(freeT_stream . stream_freeT) x
= freeT_stream (FreeT (go x))
= Effect (go x >>= \case
    Pure r -> return (Return r)
    Free f -> return (Step (fmap freeT_stream f)))

案例x = Step f ,歸納假設(IH) fmap (freeT_stream . stream_freeT) f = f

= Effect (return (Step (fmap freeT_stream (fmap stream_freeT f))))
= Effect (return (Step f))  -- by IH
= Step f  -- by quotient

案例x = Return r

= Effect (return (Return r))
= Return r   -- by quotient

情況x = Effect m ,歸納假設m >>= (return . freeT_stream . stream_freeT)) = m

= Effect ((m >>= go) >>= \case ...)
= Effect (m >>= \x' -> go x' >>= \case ...)  -- monad law
= Effect (m >>= \x' -> return (Effect (go x' >>= \case ...)))  -- by quotient
= Effect (m >>= \x' -> (return . freeT_stream . stream_freeT) x')  -- by the first two equations above in reverse
= Effect m  -- by IH

匡威作為練習。

使用Return示例和具有嵌套Effect構造函數的示例都不能由具有相同參數fm FreeT表示。 還有更多反例。 數據類型的潛在差異最好在手動波形空間中看到,其中數據構造函數被剝離並且允許無限類型。

兩個Stream fmaFreeT fma是嵌套的a一堆內部類型fm類型構造函數。 Stream允許任意嵌套fm ,而FreeT更加嚴格。 它總是有一個外部m 它包含f和另一個m並重復,或a和終止。

但這並不意味着類型之間沒有某種等價物。 您可以通過顯示每種類型可以忠實地嵌入另一種類型中來顯示一些等效性。

FreeT嵌入一​​個Stream可以在一個觀察的背面完成:如果選擇f'm'使得fm類型構造函數在每個級別都是可選的,則可以模擬fm任意嵌套。 一種快速的方法是使用Data.Functor.Sum ,然后編寫一個函數:

streamToFreeT :: Stream f m a -> FreeT (Sum Identity f) (Sum Identity m) a
streamToFreeT = undefined -- don't have a compiler nearby, not going to even try

請注意,該類型將沒有必要的實例來運行。 這可以通過將Sum Identity切換為實際具有適當Monad實例的更直接類型來糾正。

向另一個方向轉變不需要任何改變類型的技巧。 FreeT的更受限制的形狀已經可以直接嵌入Stream

我說這會使文檔正確,但可能它應該使用比“等效”更精確的術語。 你可以使用一種類型構建的任何東西,你可以用另一種構造 - 但是可能會有一些額外的嵌入解釋和涉及的變量的變化。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM