Haskell 如何使用自定义应用程序类型代替IO?
我想在程序中使用自定义应用程序类型代替Haskell 如何使用自定义应用程序类型代替IO?,haskell,monad-transformers,io-monad,Haskell,Monad Transformers,Io Monad,我想在程序中使用自定义应用程序类型代替IO,并将其与async库中的函数一起使用 具体地说,我热衷于将两个类型为App的计算传递给race\uu。由于race只接受IO类型的值,因此我用return包装了这些计算 当这种类型检查时,我可以看到两种计算都没有实际执行 这里有一个简单的例子说明了这个问题: {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE DerivingStrategies #-} {-# LANGUA
IO
,并将其与async
库中的函数一起使用
具体地说,我热衷于将两个类型为App
的计算传递给race\uu
。由于race
只接受IO
类型的值,因此我用return
包装了这些计算
当这种类型检查时,我可以看到两种计算都没有实际执行
这里有一个简单的例子说明了这个问题:
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE ScopedTypeVariables #-}
module RaceTest where
import Control.Monad.Reader ( MonadReader
, ReaderT(..)
, runReaderT
)
import Control.Monad.IO.Class ( MonadIO
, liftIO
)
import Control.Concurrent.Async ( race_ )
data Env = Env { val :: !Int }
newtype App a = App
{ unApp :: ReaderT Env IO a
} deriving (Functor, Applicative, Monad, MonadIO, MonadReader Env)
runApp :: Env -> App a -> IO a
runApp env app = runReaderT (unApp app) env
main = runApp (Env 24) simpleApp
where
simpleApp :: App () = do
liftIO $ putStrLn "About to spawn threads"
liftIO $ race_ (return firstAsync) (return secondAsync)
firstAsync :: App () = liftIO $ putStrLn "First async"
secondAsync :: App () = liftIO $ putStrLn "Second async"
如何使用race
运行App
类型的计算
尽管在本例中简单地去掉
App
类型,但在我正在构建的应用程序中,我有App
和Env
类型,它们允许使用与此类似的co log
进行日志记录。这是我不想失去的东西。您的计算没有得到执行,因为您实际上没有将它们传递给race
。相反,您正在传递两个IO
计算,结果返回您的App
计算。但不是执行它们
为了让它们在IO
中执行,请使用您已有的函数runApp
。由于您需要向它传递一个环境,并且我假设您希望使用与simpleApp
本身相同的环境,因此您可以使用ask
从Monawarder
上下文中获取它:
simpleApp :: App () = do
liftIO $ putStrLn "About to spawn threads"
env <- ask
liftIO $ race_ (runApp env firstAsync) (runApp env secondAsync)
simpleApp::App()=do
liftIO$putStrLn“即将生成线程”
你可能会考虑使用“unLIFITiO”包提供诸如<代码> race> <代码>之类的函数,它们在任何一个单元格上都有一个<代码> MonadUnliftIO < /Calp>实例(基本上,它们处理所有的新类型的包装和解包)。code>ReaderT
overIO
已经有这样的实例,您可以为您的新类型派生一个实例。