Haskell 每个处理器读取器的Scotty monad转换器

Haskell 每个处理器读取器的Scotty monad转换器,haskell,monad-transformers,scotty,Haskell,Monad Transformers,Scotty,问题中展示了如何使用ScottyT在堆栈中嵌入读取器monad来访问静态配置(在这种情况下,连接池) 我有一个类似的问题,但更简单——或者至少我这么认为 我想将阅读器添加到单个处理程序(即ActionT),而不是整个应用程序 我从上面的问题开始修改程序,但我不知道如何将actiontext(ReaderT String IO)转换为处理程序需要的actiontext IO。在摸索和尝试使用键入的孔,希望看到如何建设这一点,我现在不得不放弃,并寻求帮助。我真的觉得这应该很简单,但不知道如何做到这一

问题中展示了如何使用
ScottyT
在堆栈中嵌入
读取器
monad来访问静态配置(在这种情况下,连接池)

我有一个类似的问题,但更简单——或者至少我这么认为

我想将
阅读器
添加到单个处理程序(即
ActionT
),而不是整个应用程序

我从上面的问题开始修改程序,但我不知道如何将
actiontext(ReaderT String IO)
转换为处理程序需要的
actiontext IO
。在摸索和尝试使用键入的孔,希望看到如何建设这一点,我现在不得不放弃,并寻求帮助。我真的觉得这应该很简单,但不知道如何做到这一点

这是程序,突出显示了我被卡住的几行:

{-# LANGUAGE OverloadedStrings #-}

import qualified Data.Text.Lazy as T
import           Data.Text.Lazy (Text)
import           Control.Monad.Reader
import           Web.Scotty.Trans

type ActionD = ActionT Text (ReaderT String IO)

main :: IO ()
main = do
  scottyT 3000 id id app

-- Application
app ::  ScottyT Text IO ()
app = do
  get "/foo" $ do
    h <- handler              -- ?
    runReaderT h "foo"        -- ?
--get "/bar" $ do
--  h <- handler
--  runReaderT h "bar"

-- Route action handler
handler ::  ActionD ()
handler = do
  config <- lift ask
  html $ T.pack $ show config
{-#语言重载字符串}
将限定的Data.Text.Lazy作为T导入
导入Data.Text.Lazy(文本)
导入控制.Monad.Reader
导入Web.Scotty.Trans
类型ActionD=ActionT文本(读取字符串IO)
main::IO()
main=do
scottyT 3000 id应用程序
--应用
应用程序::ScottyT文本IO()
app=do
获取“/foo”$do

h如果希望在单独的读取器中运行每个操作,则根本不需要更复杂的
Scotty.Trans
接口。您只需以另一种方式构建monad堆栈,将
ReaderT
放在顶部

import qualified Data.Text.Lazy as T
import           Control.Monad.Reader
import           Web.Scotty

type ActionD = ReaderT String ActionM

main :: IO ()
main = do
  scotty 3000 app

-- Application
app ::  ScottyM ()
app = do
  get "/foo" $ do
    runReaderT handler "foo"

-- Route action handler
handler ::  ActionD ()
handler = do
  config <- ask
  lift $ html $ T.pack $ show config
将限定的Data.Text.Lazy导入为T
导入控制.Monad.Reader
导入Web.Scotty
类型ActionD=ReaderT字符串ActionM
main::IO()
main=do
scotty 3000应用程序
--应用
应用程序::ScottyM()
app=do
获取“/foo”$do
runReaderT处理程序“foo”
--路由操作处理程序
处理程序::ActionD()
handler=do

这很有趣。我不知道如何以一种通用的方式实现这一点——这可能需要拆开
ActionT
并重新构建它。但是,那种类型是不透明的,所以我们不能…哦。嗯,也许你是对的。当然,我可以明确地将配置传递给处理程序,然后再传递给它们调用的函数,但我有一个模糊的想法,即每当这样做时,都可以使用
读取器
。问题似乎是将
t1(t2m)a
转化为
t1 m a
,其中
t1,t2
是单子变压器。或者,更一般地说,
tm1a
转化为
tm2a
,其中
m1,m2
是单子。这看起来像是对
t
的函子ish要求:给定
f::forall b。m1 b->m2 b
您想要
fmapT f::t m1 a->t m2 a
。也许不是所有的转换器都允许
fmapT
,但这可能是一个单独的类型类。或者也许有某种方法可以用我现在没有看到的标准工具来制作它:-/对。我想这就是办法。对于
ActionM
操作,我宁愿避免
lift
s,因为
Reader
操作会少得多,但这可能是不可避免的。