簡體   English   中英

操作真的與一個免費的monad同構嗎?

[英]Is operational really isomorphic to a free monad?

證明

這篇博文中,Tekmo指出我們可以證明ExitSuccess退出是因為(我認為)它就像構造函數的Const函子(它不帶x因此fmap行為類似於const )。

通過操作包,Tekmo的TeletypeF可能會被翻譯成如下:

data TeletypeI a where
    PutStrLn :: String -> TeletypeI ()
    GetLine :: TeletypeI String
    ExitSuccess :: TeletypeI ()

我已經讀過,操作與一個免費monad是同構的,但我們可以在這里證明ExitSuccess退出嗎? 在我看來它遇到了與exitSuccess :: IO ()完全相同的問題,特別是如果我們要為它編寫一個解釋器,我們需要把它寫成就像它沒有退出一樣:

eval (ExitSuccess :>>= _) = exitSuccess

與不涉及任何模式通配符的免費monad版本相比:

run (Free ExitSuccess) = exitSuccess

怠惰

操作Monad教程中, apfelmus提到了一個缺點:

狀態monad表示為s - >(a,s)可以應對一些無限的程序,如

 evalState (sequence . repeat . state $ \\s -> (s,s+1)) 0 

而指令列表方法沒有希望處理它,因為只有最后一個Return指令才能返回值。

對於免費的monad也是如此嗎?

(請允許我通過大膽結合以前的答案來獲得大獎。;-))

關鍵的觀察是:證明究竟是什么? 根據Free TeletypeF的表述,我們可以證明以下內容:

Free TeletypeF a類型程序的每個解釋器在遇到ExitSuccess指令時必須退出。 換句話說,我們自動獲得代數定律

  interpret (exitSuccess >>= k) = interpret exitSuccess 

因此, Free monad實際上允許您將某些代數定律烘焙到該類型中。

相反,操作方法不限制ExitSuccess的語義,沒有與每個解釋器相關的相關代數法。 可以編寫在遇到此指令時退出的解釋器,但也可以編寫不能解釋的解釋器。

當然,您可以通過檢查證明任何特定的解釋器滿足法律,例如因為它使用通配符模式匹配。 Sjoerd Visscher觀察到您還可以通過將ExitSuccess的返回類型ExitSuccessVoid來在類型系統中強制執行此操作。 然而,這不適用於可以融入自由單子的其他法律,例如mplus指令的分配法則。

因此,在一個令人困惑的事件轉變中,如果你將“自由”解釋為“最少量的代數定律”,那么操作方法比免費monad更自由。

這也意味着這些數據類型不是同構的。 但是,它們是等價的:每個用Free編寫的解釋器都可以轉換成用Program編寫的解釋器,反之亦然。

就個人而言,我喜歡將我的所有法律都放入翻譯中,因為有許多法律無法融入免費的monad中,我喜歡將它們全部放在一個地方。

答案是肯定的,但僅當您使用TeletypeF的其他翻譯時:

data TeletypeI a where
    PutStrLn :: String -> TeletypeI ()
    GetLine :: TeletypeI String
    ExitSuccess :: TeletypeI Void

TeletypeI的論點是操作將/必須提供給程序的其余部分。 它是繼續k in的參數的類型

eval (ExitSuccess :>>= k) = ...

由於沒有Void類型的值,我們可以確定永遠不會調用k (一如既往,我們必須忽略undefined 。)

等效類型是:

data TeletypeI a where
    PutStrLn :: String -> TeletypeI ()
    GetLine :: TeletypeI String
    ExitSuccess :: TeletypeI a

現在我們必須為k匹配任何類型提供一個值,我們也不能這樣做。 這可能更實用,因為singleton ExitSuccess現在具有靈活類型Program TeletypeI a

類似地, exitSuccess可以通過給它類型IO VoidIO a來修復。

答案是否定的,你無法證明操作者忽略了exitSuccess上的其余程序。 TeletypeITeletypeF對比以了解原因。 為了便於比較,我將用GADT表示法重寫TeletypeF

data TeletypeF x where                     | data TeletypeI x where
  PutStrLn :: String -> x  -> TeletypeF x  |   PutStrLn :: String -> TeletypeI ()
  GetLine :: (String -> x) -> TeletypeF x  |   GetLine :: TeletypeI String
  ExitSuccess ::              TeletypeF x  |   ExitSuccess :: TeletypeI ()

使用TeletypeF ,我們可以立即構建實際程序:

GetLine (\str -> PutStrLn (map toUpper str) ExitSuccess)

TeletypeI不拿出一個辦法來指代“節目的其余部分”,因為同樣的方式TeletypeF一樣。

-- TeletypeF:
GetLine (\str -> "rest of program" goes here)
-- or
PutStrLn someString ("rest of program" goes here)
-- or
ExitSuccess -- there is no "rest of program" slot provided

由於TeletypeI缺少此“程序的其余部分”信息,因此當您遇到ExitSuccess時,您將無法獲得任何知識。

-- TeletypeI
PutStrLn someString -- no information about "rest of program"
-- or
GetLine -- no information about "rest of program"
-- or
ExitSuccess -- no information about "rest of program"

允許來的是“程序的其余部分”完全取決於Program類型,它對應用它的指令集一無所知。 它只允許您將指令綁定在一起,並通過Return終止。

暫無
暫無

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

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