电梯在 MT 堆栈中的组成
composition of lift's in MT stack
我很难理解这个编译错误。代码如下:
#!/usr/bin/env stack
-- stack script --resolver lts-8.22
{-# LANGUAGE OverloadedStrings #-}
import Network.HTTP.Simple
import qualified Data.ByteString as BS
import Control.Monad.Reader
import Control.Monad.Except
import Control.Monad.Trans.Class
import Data.Conduit
type Cmd i o = ReaderT (BS.ByteString) (ExceptT HttpException (ConduitM i o IO))
runCmd :: Cmd i o a -> BS.ByteString -> ConduitM i o IO (Either HttpException a)
runCmd cmdTS host = runExceptT $ runReaderT cmdTS host
readHost :: Cmd () BS.ByteString ()
readHost = do
host <- ask
let req = setRequestMethod "GET"
$ setRequestHost host
$ defaultRequest
lift . lift $ httpSource req getResponseBody
基本上我有一个 4 层的 MT 堆栈,在 readHost
中,我试图将一个对象从第二层提升到底层到顶层,所以我有两个 lift
组合在一起。但遗憾的是,代码无法编译,我收到以下错误:
[-Wdeferred-type-errors]
• No instance for (Control.Monad.Trans.Resource.Internal.MonadResource
IO)
arising from a use of ‘httpSource’
• In the second argument of ‘($)’, namely
‘httpSource req getResponseBody’
In a stmt of a 'do' block:
lift . lift $ httpSource req getResponseBody
In the expression:
do host <- ask
let req
= setRequestMethod "GET" $ setRequestHost host $ defaultRequest
lift . lift $ httpSource req getResponseBody
请帮助我理解此错误消息的含义。附带一提,我还没有看到有人用 ConduiT
坐在底部来构建这样的堆栈,所以我猜这是不好的做法? "design pattern"这里有什么好?我知道 "design patter" 这个词在 haskell 中不存在,但我想不出更好的词。非常感谢!
我首先减少了 monad t运行sformer 栈中的层数来缩小你的
代码:
#!/usr/bin/env stack
-- stack script --resolver lts-8.22
{-# LANGUAGE OverloadedStrings #-}
import Network.HTTP.Simple
import qualified Data.ByteString as BS
import Control.Monad.Reader
import Control.Monad.Except
import Control.Monad.Trans.Class
import Data.Conduit
type Cmd i o = ConduitM i o IO
readHost :: BS.ByteString -> Cmd () BS.ByteString ()
readHost host = do
let req = setRequestMethod "GET" . setRequestHost host $ defaultRequest
httpSource req getResponseBody
然后我 运行 stack {scriptname}
得到了一个与你得到的非常相似的错误
对于更大的堆栈:
{scriptname}:17:3: error:
• No instance for (resourcet-1.1.9:Control.Monad.Trans.Resource.Internal.MonadResource
IO)
arising from a use of ‘httpSource’
• In a stmt of a 'do' block: httpSource req getResponseBody
In the expression:
do { let req
= setRequestMethod "GET" . setRequestHost host $ defaultRequest;
httpSource req getResponseBody }
In an equation for ‘readHost’:
readHost host
= do { let req = ...;
httpSource req getResponseBody }
弄清楚这个较小的案例很可能会产生更复杂的版本
更容易对付。
让我们看看 httpSource
的类型:
httpSource :: (MonadResource m, MonadIO n) =>
Request
-> (Response (ConduitM i ByteString n ()) -> ConduitM i o m r)
-> ConduitM i o m r
它的 return 类型是 ConduitM i o m r
其中 m
必须是
MonadResource
.
现在让我们再看一下 readHost
的最终 return 类型。
Cmd () BS.ByteString ()
只不过是
ConduitM () BS.ByteString IO ()
伪装。
比较 Conduit () BS.ByteString IO ()
和 ConduitM i o m r
可以看出
m
对应 IO
.
IO
是 MonadResource
的实例吗?根据 GHC,它不是。
使用 Hoogle 环顾四周让我们知道 ResourceT IO
是一个
MonadResource
的实例。让我们在程序中尝试一下。
-- stack script --resolver lts-8.22
{-# LANGUAGE OverloadedStrings #-}
import Network.HTTP.Simple
import qualified Data.ByteString as BS
import Control.Monad.Reader
import Control.Monad.Except
import Control.Monad.Trans.Class
import Control.Monad.Trans.Resource
import Data.Conduit
main :: IO ()
main = putStrLn "hello"
type Cmd i o = ConduitM i o (ResourceT IO)
readHost :: BS.ByteString -> Cmd () BS.ByteString ()
readHost host = do
let req = setRequestMethod "GET" . setRequestHost host $ defaultRequest
httpSource req getResponseBody
这编译没有错误,也打印到标准输出。
我相信您可以将此修复程序用于较大的程序。至少它解释了错误。
我很难理解这个编译错误。代码如下:
#!/usr/bin/env stack
-- stack script --resolver lts-8.22
{-# LANGUAGE OverloadedStrings #-}
import Network.HTTP.Simple
import qualified Data.ByteString as BS
import Control.Monad.Reader
import Control.Monad.Except
import Control.Monad.Trans.Class
import Data.Conduit
type Cmd i o = ReaderT (BS.ByteString) (ExceptT HttpException (ConduitM i o IO))
runCmd :: Cmd i o a -> BS.ByteString -> ConduitM i o IO (Either HttpException a)
runCmd cmdTS host = runExceptT $ runReaderT cmdTS host
readHost :: Cmd () BS.ByteString ()
readHost = do
host <- ask
let req = setRequestMethod "GET"
$ setRequestHost host
$ defaultRequest
lift . lift $ httpSource req getResponseBody
基本上我有一个 4 层的 MT 堆栈,在 readHost
中,我试图将一个对象从第二层提升到底层到顶层,所以我有两个 lift
组合在一起。但遗憾的是,代码无法编译,我收到以下错误:
[-Wdeferred-type-errors]
• No instance for (Control.Monad.Trans.Resource.Internal.MonadResource
IO)
arising from a use of ‘httpSource’
• In the second argument of ‘($)’, namely
‘httpSource req getResponseBody’
In a stmt of a 'do' block:
lift . lift $ httpSource req getResponseBody
In the expression:
do host <- ask
let req
= setRequestMethod "GET" $ setRequestHost host $ defaultRequest
lift . lift $ httpSource req getResponseBody
请帮助我理解此错误消息的含义。附带一提,我还没有看到有人用 ConduiT
坐在底部来构建这样的堆栈,所以我猜这是不好的做法? "design pattern"这里有什么好?我知道 "design patter" 这个词在 haskell 中不存在,但我想不出更好的词。非常感谢!
我首先减少了 monad t运行sformer 栈中的层数来缩小你的 代码:
#!/usr/bin/env stack
-- stack script --resolver lts-8.22
{-# LANGUAGE OverloadedStrings #-}
import Network.HTTP.Simple
import qualified Data.ByteString as BS
import Control.Monad.Reader
import Control.Monad.Except
import Control.Monad.Trans.Class
import Data.Conduit
type Cmd i o = ConduitM i o IO
readHost :: BS.ByteString -> Cmd () BS.ByteString ()
readHost host = do
let req = setRequestMethod "GET" . setRequestHost host $ defaultRequest
httpSource req getResponseBody
然后我 运行 stack {scriptname}
得到了一个与你得到的非常相似的错误
对于更大的堆栈:
{scriptname}:17:3: error:
• No instance for (resourcet-1.1.9:Control.Monad.Trans.Resource.Internal.MonadResource
IO)
arising from a use of ‘httpSource’
• In a stmt of a 'do' block: httpSource req getResponseBody
In the expression:
do { let req
= setRequestMethod "GET" . setRequestHost host $ defaultRequest;
httpSource req getResponseBody }
In an equation for ‘readHost’:
readHost host
= do { let req = ...;
httpSource req getResponseBody }
弄清楚这个较小的案例很可能会产生更复杂的版本 更容易对付。
让我们看看 httpSource
的类型:
httpSource :: (MonadResource m, MonadIO n) =>
Request
-> (Response (ConduitM i ByteString n ()) -> ConduitM i o m r)
-> ConduitM i o m r
它的 return 类型是 ConduitM i o m r
其中 m
必须是
MonadResource
.
现在让我们再看一下 readHost
的最终 return 类型。
Cmd () BS.ByteString ()
只不过是
ConduitM () BS.ByteString IO ()
伪装。
比较 Conduit () BS.ByteString IO ()
和 ConduitM i o m r
可以看出
m
对应 IO
.
IO
是 MonadResource
的实例吗?根据 GHC,它不是。
使用 Hoogle 环顾四周让我们知道 ResourceT IO
是一个
MonadResource
的实例。让我们在程序中尝试一下。
-- stack script --resolver lts-8.22
{-# LANGUAGE OverloadedStrings #-}
import Network.HTTP.Simple
import qualified Data.ByteString as BS
import Control.Monad.Reader
import Control.Monad.Except
import Control.Monad.Trans.Class
import Control.Monad.Trans.Resource
import Data.Conduit
main :: IO ()
main = putStrLn "hello"
type Cmd i o = ConduitM i o (ResourceT IO)
readHost :: BS.ByteString -> Cmd () BS.ByteString ()
readHost host = do
let req = setRequestMethod "GET" . setRequestHost host $ defaultRequest
httpSource req getResponseBody
这编译没有错误,也打印到标准输出。
我相信您可以将此修复程序用于较大的程序。至少它解释了错误。