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
。我要问的是(如果可能的话)如何(如果可能的话)用newMyType 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))