我正在尝试使用 ReaderT monad 转换器方法通过我的基于 Scotty 的应用程序进行线程配置,但在这样做时遇到了麻烦。在定义路由(因为其中一些取决于配置)和处理实际请求时,我都必须使用配置。
后者在 ActionT 中工作得很好,但无论我尝试什么,我都无法在 ScottyT 中获得正确的类型。
这是我从 Scotty GitHub 存储库中的 ReaderT 示例编译的最小示例:
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE OverloadedStrings #-}
module Main where
import Control.Applicative
import Control.Monad.Reader (MonadIO, MonadReader, ReaderT, asks, lift, runReaderT)
import Data.Default.Class (def)
import Data.Text.Lazy (Text, pack)
import Prelude
import Web.Scotty.Trans (ScottyT, get, scottyOptsT, text, capture)
data Config = Config
{ environment :: String
} deriving (Eq, Read, Show)
newtype ConfigM a = ConfigM
{ runConfigM :: ReaderT Config IO a
} deriving (Applicative, Functor, Monad, MonadIO, MonadReader Config)
application :: ScottyT Text ConfigM ()
application = do
get "/" $ do
e <- lift $ asks environment
text $ pack $ show e
path <- lift $ asks environment
get (capture path) $ do
text $ pack $ "Hello, custom path"
main :: IO ()
main = scottyOptsT def runIO application where
runIO :: ConfigM a -> IO a
runIO m = runReaderT (runConfigM m) config
config :: Config
config = Config
{ environment = "Development"
}
我得到的错误是:
• No instance for (Control.Monad.Trans.Class.MonadTrans
(ScottyT Text))
arising from a use of ‘lift’
• In a stmt of a 'do' block: path <- lift $ asks environment
我查看了概述 ScottyT 类型的代码,实际上似乎没有为它定义 MonadTrans 的实例。
但是,我觉得我没有足够的法力和 Haskell 经验来找到摆脱它的方法,希望能提供任何帮助!
谢谢!