haskell - MonadBaseControl : how to lift simpleHTTP from Happstack?

标签 haskell monads monad-transformers

如何使用MonadBaseControl来自 monad-control抬起simpleHTTP happstack-server 中定义的函数?

simpleHTTP 的当前类型:

simpleHTTP :: ToMessage a 
           => Conf -> ServerPartT IO a -> IO () 

simpleHTTPLifted 的预期类型:

simpleHTTPLifted :: (MonadBaseControl IO m, ToMessage a)
                 => Conf -> ServerPartT m a -> m ()

我目前的尝试(不编译):

simpleHTTPLifted conf action =
   liftBaseWith (\runInBase ->
              let
                  fixTypes :: UnWebT m a -> UnWebT IO a
                  fixTypes c = runInBase c
              in simpleHTTP conf (mapServerPartT fixTypes action)
           )

请注意,类似的难题在我的相关问题中:MonadBaseControl: how to lift ThreadGroup

我想了解一般情况下如何提升此类功能以及遇到此类难题时通常采取的步骤是什么?

编辑:我想我需要一个类型为 (StM m a -> a) 的函数。 restoreM 非常接近,但没有成功。我还发现了一个丑陋的 fixTypes 版本:

fixTypes :: UnWebT m a -> UnWebT IO a
fixTypes c = do
    x <- newIORef undefined
    _ <- runInBase (c >>= liftBase . writeIORef x)
    readIORef x

这依赖于 IO 作为基础 monad,这不是最佳解决方案。

最佳答案

我认为您一般无法为任何 MonadBaseControl IO m 解除此限制。有一些 m 我们可以做到。

一般情况

UnWebT m 同构于 WebT m它有一个 MonadTransControl实例。您可以使用 mkWebT::UnWebT m a -> WebT m aununWebT::WebT m a -> UnWebT m aWebT 相互转换。

MonadBaseControl 是一个奇特的包装器,围绕着一堆 MonadTransControl 更改器(mutator),它使堆栈变平,以便运行和恢复状态一直发生在堆栈中并一直返回再顶一下你可以通过理解 MonadTransControl 来理解 MonadBaseControl,我将在这里简单地重复一下:

class MonadTrans t => MonadTransControl t where
  data StT t :: * -> *
  liftWith :: Monad m => (Run t -> m a) -> t m a
  restoreT :: Monad m => m (StT t a) -> t m a

type Run t = forall n b. Monad n => t n b -> n (StT t b)

该类(class)用 liftWith 说,“我将提供一种在 m 中运行 t m 的临时方法,您可以使用它在 m 中构建操作,我将依次运行它。”结果的 StT 类型表示,“我在 m 中为您运行的 t m 结果不会普遍可用in t m; 我需要在某个地方保存我的状态,如果你想要结果,你必须给我一个恢复我状态的机会。”

表达大致相同的另一种方式是,“我可以暂时解开基础 monad”。实现 fixTypes 的问题被简化为“鉴于我们可以暂时从 m 解包一个 WebT 并且可以暂时解包一个 m来自 IO,我们可以从 IO 中永久解包 m 吗?”除非 IO 的功能,否则答案几乎肯定是“否”。

IO 技巧

我怀疑存在 m 使得“丑陋的”fixTypes 会做一些可怕的事情,比如从不调用 writeIORef 并因此返回 undefined 或异步执行代码,因此在 readIORef 之后调用 writeIORef。我不确定。由于 liftBaseWith 创建的操作可能永远不会在这种退化的情况下使用,因此这使得推理变得复杂。

对于 Comonads

当 monad m 的状态为 Comonad 时,应该有一种方法可以在不使用 IO 技巧的情况下提升 simpleHttp因此有一个函数 extract::StM m a -> a。例如,StateT s m 就是这种情况,它本质上具有 StM s a ~ (s, a)

{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE ScopedTypeVariables #-}

import Happstack.Server.SimpleHTTP

import Control.Comonad
import Control.Monad.Base
import Control.Monad.Trans.Control

simpleHTTPLifted :: forall m a. (MonadBaseControl IO m, Comonad (StM m), ToMessage a)
                 => Conf -> ServerPartT m a -> m ()
simpleHTTPLifted conf action =
    liftBaseWith (\runInBase ->
        let
            fixTypes :: UnWebT m b -> UnWebT IO b
            fixTypes = fmap extract . runInBase
        in simpleHTTP conf (mapServerPartT fixTypes action)
    )

在实践中,这不是很有用,因为在旧版本的 monad-control 中定义的 newtype 没有 Comonad 实例,并且类型同义词在较新版本的 monad-control 不会努力将结果作为最后一个类型参数。例如,在最新版本的 monad-control type StT (StateT s) a = (a, s) 中。

关于haskell - MonadBaseControl : how to lift simpleHTTP from Happstack?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27733699/

相关文章:

string - 是否有不加引号的多态 `toString` 函数?

haskell - Control.MonadPlus.Free 出了什么问题?

scala - TailRec 和 State monad 的组成

haskell - 找不到模块 ‘Text.Regex.Posix’

haskell - IO Monad 记录更新失败?

Haskell 改变 IO 函数的状态

haskell - 如何测试自定义 StateT 的 Monad 实例?

haskell - 将带有 monad 参数的函数提升到 monad 转换器中

haskell - vim haskell 模式的视频或教程

haskell - 为什么 "let"语句会强制 "applicative do" block 需要 monad 约束?