屈服/等待功能延续单子我想创建一个类型像这样的自动机类型:在哈斯克尔
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)来获得更好的渐进性能。 –