温馨提示:本文翻译自stackoverflow.com,查看原文请点击:haskell - How to use custom App type in place of IO?
haskell monad-transformers io-monad

haskell - 如何使用自定义应用类型代替IO?

发布于 2020-04-10 11:48:20

我想在适当位置使用自定义的应用程序类型的IO在我的计划,并与像函数使用它race_async图书馆。

具体来说,我很想将type的两个计算传递Apprace_由于race_只接受type的值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"

我怎样才能运行型的这些计算App使用race_


¹ 尽管在本例中,简单地摆脱App类型很简单,但是在我正在构建的应用程序中,我拥有AppEnv类型,这些类型允许使用co-log类似于此设置的日志记录那是我不想失去的东西。

查看更多

提问者
Matthias Braun
被浏览
93
Fyodor Soikin 2020-02-01 23:38

您的计算没有得到执行,因为您实际上没有将它们传递给race_相反,您要传递两个IO计算,这些计算将返回App结果。但是不执行它们。

为了使它们在内部执行IO,请使用您runApp已有的函数由于您需要向其传递环境,并且假设您要使用与其simpleApp本身相同的环境,因此可以askMonadReader上下文中获取它

simpleApp :: App () = do
     liftIO $ putStrLn "About to spawn threads"
     env <- ask
     liftIO $ race_ (runApp env firstAsync) (runApp env secondAsync)