我想知道为什么WAI的Aplication
类型被设计为Request -> (Response -> IO ResponseReceived) -> IO ResponseReceived
。为什么不Request -> (Response -> IO ()) -> IO ()
呢?文档说
一种特殊的数据类型,指示WAI处理程序已收到响应。这是为了避免在Application的定义中需要Rank2Types。
强烈建议只有WAI处理程序才能导入和使用此数据类型的数据构造函数。
这种特殊的数据类型如何帮助避免Rank2Types
?
答案 0 :(得分:6)
Application
应该是
type Application = Request -> (forall b. (Response -> IO b) -> IO b)
-- a.k.a. Request -> Codensity IO Response
-- newtype Codensity f a = Codensity { runCodensity :: forall b. (a -> f b) -> f b }
-- which is closely related to continuations
也就是说,Application
使用Request
,函数f
,并用f
调用Response
。
app :: Application
app req f = f _resp
Application
强制您致电f
。除了IO b
之外,没有其他函数可以在app
内产生f
,因此,由于app
必须产生IO b
,app
必须致电f
。 wai
依赖于app
调用f
,它可以通过此Application
来强制实施。但是,Application
的排名较高,这在某种程度上是不可取的。
实际使用的解决方案是:
type Application = Request -> (Response -> IO ResponseReceived) -> IO ResponseReceived
-- a.k.a. Request -> ContT ResponseReceived IO Response
-- in general, ContT is "bigger" and "weaker" than Codensity
-- but, in exchange, does not require higher ranked types
app :: Application
app req f = f _resp
f
仍然是app
手上唯一可以产生ResponseReceived
的东西,只要app
不违反与{{ 1}},然后导入构造函数。您不能将wai
替换为ResponseReceived
。每个人及其母亲都可以使用()
的构造函数(()
)。我认为不甚至不可能。这使其不适用于()
:
Application