haskell - Haskell 中的 Yield/Await 函数的延续 monad

标签 haskell monads continuation

我想创建一个具有如下类型的自动机类型:

newtype Auto i o = Auto {runAuto :: i -> (o, Auto i o)}

我知道这是 Automata arrow 的类型,但我不是在寻找箭头。我想让它成为一个单子(monad),所以大概它会有这样的类型

newtype Auto i o a = ???? What goes here?

具有这样的功能:

yield :: o -> Auto i o i

因此,当我从 Auto monad 中调用“yield”时,“runAuto”函数返回一对由“yield”参数和延续函数组成的对。当应用程序调用延续函数时,参数将作为“yield”的结果在 monad 中返回。

我知道这需要一些延续单子(monad)的风格,但尽管过去曾与延续争论过,但我不知道如何编写这个代码。

我也知道这很像 Michael Snoyman 的 Conduit monad ,除了他将“yield”和“await”分开。这个 monad 必须为每个输入提供一个输出。

背景:我正在编写一些以复杂方式响应 GUI 事件的代码。我希望能够编写接受一系列输入的代码,以换取随着用户交互的进行而对屏幕进行更新,而不是将其变成手动编码的状态机。

编辑

事实证明这一切都是错误的。我编写了 Petr Pudlák 在他的回复中建议的代码,它似乎有效,但“yield”操作总是从先前 yield 中产生输出。这很奇怪。

长时间盯着屏幕后,我终于发现我需要粘贴在这里的代码。关键的区别在于 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

最佳答案

该类型是 Mealy 机器。请参阅https://hackage.haskell.org/package/machines-0.5.1/docs/Data-Machine-Mealy.html对于一堆实例 - 但请注意,Monad 实例总是会很慢,因为它需要根据 monad 定律进行对角化。

听起来你真正想要的是 auto package无论如何。

关于haskell - Haskell 中的 Yield/Await 函数的延续 monad,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31358856/

相关文章:

haskell - 无法使用 IO Monad 打印到文件

java - 如何使用 Monadic Bind 简化此 Apache Tomcat 代码?

java - 如何保存java程序的状态并在以后调用它?

haskell - 无点风格并使用 $

haskell - 傻瓜类型系列

scala - 在 for-comprehension 中使用不同的 monad

C# 等待与延续 : not quite the same?

haskell - 在 haskell 中一般遍历树的最简单方法

haskell - Haskell 的非严格语义对求值策略有什么要求?

command-line - 什么是 Redis 命令行 (redis-cli) 续行符?