屈服/等待功能延續單子我想創建一個類型像這樣的自動機類型:在哈斯克爾
newtype Auto i o = Auto {runAuto :: i -> (o, Auto i o)}
我知道這是Automata arrow的類型,但我沒有找一個箭頭。我想使這個單子,所以推測其將有一種像
newtype Auto i o a = ???? What goes here?
具有這樣的功能:
yield :: o -> Auto i o i
所以,當我打電話從內自動單子的「產量」 「runAuto」函數返回一個由「yield」參數和continuation函數組成的對。當應用程序調用continuation函數時,參數將作爲「yield」的結果在monad中返回。
我知道這將需要一些延續單子的味道,但儘管過去我已經與延續爭執,我看不出如何編碼這一個。
我也知道這與Michael Snoyman的Conduit monad非常相似,只不過他分裂了「收益」和「等待」。這個monad每個輸入都必須有一個輸出。
背景:我正在編寫一些以複雜的方式響應GUI事件的代碼。我希望能夠編寫接受一系列輸入的代碼,以便隨着用戶交互的進行產生更新屏幕,而不是將其轉換爲手動編碼的狀態機。
編輯
這一切都被證明是錯誤的巧妙。我寫了PetrPudlák在他的回覆中提出的代碼,似乎可行,但「收益率」操作始終產生了先前的收益率。哪一個很奇怪。
經過多次盯着屏幕後,我終於明白,我需要粘貼在這裏的代碼。關鍵的區別在於AutoF類型。比較下面的和Petr提出的那個。
import Control.Applicative
import Control.Monad
import Control.Monad.IO.Class
import Control.Monad.State.Class
import Control.Monad.Trans.Class
import Control.Monad.Trans.Free
import Data.Void
class (Monad m) => AutoClass i o m | m -> i, m -> o where
yield :: o -> m i
data AutoF i o a = AutoF o (i -> a)
instance Functor (AutoF i o) where
fmap f (AutoF o nxt) = AutoF o $ \i -> f $ nxt i
newtype AutoT i o m a = AutoT (FreeT (AutoF i o) m a)
deriving (Functor, Applicative, Monad, MonadIO, MonadTrans, MonadState s)
instance (Monad m) => AutoClass i o (AutoT i o m) where
yield v = AutoT $ liftF $ AutoF v id
runAutoT :: (Monad m) => AutoT i o m Void -> m (o, i -> AutoT i o m Void)
runAutoT (AutoT step) = do
f <- runFreeT step
case f of
Pure v -> absurd v
Free (AutoF o nxt) -> return (o, AutoT . nxt)
-- Quick test
--
-- > runTest testStart
testStart :: Int -> AutoT Int Int IO Void
testStart x = do
liftIO $ putStrLn $ "My state is " ++ show x
y <- liftIO $ do
putStrLn "Give me a number: "
read <$> getLine
v1 <- yield $ x + y
liftIO $ putStrLn $ "I say " ++ show v1
v2 <- yield $ 2 * v1
testStart v2
runTest auto = do
putStrLn "Next input:"
v1 <- read <$> getLine
(v2, nxt) <- runAutoT $ auto v1
putStrLn $ "Output = " ++ show v2
runTest nxt
幾乎正是我想要的,除了「yield」還需要在下一個狀態轉換的新輸入,所以它應該是「yield :: o - > Auto i o i」。所以推測是「yield x = liftF(AutoF $ \ v - >(x,v))」。不過,感謝大家深入瞭解免費monads是我所需要的。過去我已經閱讀過關於它們的內容,但沒有將它們與這個特定的問題聯繫起來。當然,現在它非常明顯。 –
確實,這將是你想要的語義的「yield」的正確定義。 –
你也可以考慮使用['Codensity'](https://hackage.haskell.org/package/kan-extensions-4.2.2/docs/Control-Monad-Codensity.html)來獲得更好的漸進性能。 –