Haskell 与StateT、ST和IO合作

Haskell 与StateT、ST和IO合作,haskell,coroutine,state-monad,io-monad,st-monad,Haskell,Coroutine,State Monad,Io Monad,St Monad,我在尝试组合一组单子时遇到了一些麻烦 我使用的是,状态和镜头(因为我有很深的嵌套状态) 我有一个初步的解决方案。这里的要点是,我可以请求在协同程序之外执行IO任务 {-# LANGUAGE ExistentialQuantification #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE UndecidableInstances

我在尝试组合一组单子时遇到了一些麻烦

我使用的是,状态和镜头(因为我有很深的嵌套状态)

我有一个初步的解决方案。这里的要点是,我可以请求在协同程序之外执行
IO
任务

{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE FlexibleInstances         #-}
{-# LANGUAGE MultiParamTypeClasses     #-}
{-# LANGUAGE UndecidableInstances      #-}

module Main where

import           Control.Monad.Coroutine      (Coroutine(..), suspend, resume)
import           Control.Monad.State          (State, MonadState, MonadIO)
import           Control.Monad.State          (lift, get, put, liftIO, runState)
import           System.Environment           (getArgs)

type MyType = Coroutine IORequest (State MyState)

instance (MonadState s m) => MonadState s (Coroutine IORequest m) where
    get = lift get
    put = lift . put

io :: MonadIO m => IO a -> m a
io = liftIO

data IORequest x = forall a. RunIO (IO a) (a -> x)

instance Functor IORequest where
    fmap f (RunIO x g) = RunIO x (f . g)

data MyState = MyState { _someInt :: Int }

initialState :: MyState
initialState = MyState 1

request :: Monad m => IO a -> Coroutine IORequest m a
request x = suspend (RunIO x return)

myLogic :: MyType [String]
myLogic = do
    args <- request (io getArgs)
    request (io (print args))
    -- do a lot of useful stuff here
    return args

runMyType :: MyType [String] -> MyState -> IO ()
runMyType logic state = do
    let (req, state') = runState (resume logic) state
    case req of
        Left (RunIO cmd q') -> do
            result <- cmd
            runMyType (q' result) state'
        Right _ -> return ()

main :: IO ()
main = runMyType myLogic initialState
无论我试图想出什么,都会抛出一些关于
s
转义的错误,或者
无法将类型“s”与“s2”匹配,等等。。。也许其他的单子堆叠顺序会有帮助?还是有可能

如果您有时间,还有一个问题:上面的
MyType s
和这个有什么区别:

type MyType = forall s. Coroutine IORequest (StateT (MyState s) (ST s))

在介绍
MyType
时,您似乎使用了一个新的
MyState
(一个带有种类的
*->*
,而不仅仅是
*
)。那是
数据MyState s=MyState s
?另外,
initialState
也可以,它只是有错误的签名(
Num a=>ST s(MyState(STRef s a))
)。你可能想澄清你到底在问什么。也就是说,最后一个问题非常有趣-你会想阅读rankNTypes。@alec,你是对的,它是
data MyState s=MyState s
。我要问的是(如果可能的话)如何(如果可能的话)用new
MyType s
实现
runMyType
,因为我需要在ST monad中运行一些操作,但同时来自
Coroutine
的请求是
IO
我认为除了使用之外,您无法做到这一点。您的
runMyType
关键取决于是否能够暂停计算状态,然后将其反馈到下一轮
runState
,但是使用
ST
,一旦
runST
达到
RunIO
请求,您将无法返回到“相同的
s
”。之所以出现此错误,是因为
ST
的工作方式。试着阅读以下解释:您基本上无法从
sts
内部
runST
返回
MyState s
。如果您澄清了为什么需要
ST
,并给出了一些示例,那么可能会找到另一个解决方案,或者您的当前数据可能会被修补。
data MyState s=MyState s
根本没有意义-传递给
ST
的状态标记
s
不是“真实”类型,它应该只使用类型变量进行实例化,因此在相关位置(如值的类型)使用它只是一个语义错误。可能需要
data MyState s=MyState(STRef s Int)
initialState::ST s(STRef s MyState)
(在后一种情况下,使用原始的
data MyState=MyState Int
类型)。
type MyType = forall s. Coroutine IORequest (StateT (MyState s) (ST s))