我已经读完了 Existential Types Wikibook,它比较forall了使用小写字母来定义泛型类型。然后它说真正的用处forall是当你将它与类型类一起使用时。也就是说,forall让您的函数可以使用许多符合某种类型类的类型。
例子:
data ShowBox = forall s. Show s => SB s
Run Code Online (Sandbox Code Playgroud)
好吧,我发现了一个真正的世界用法:
spock :: forall conn sess st. SpockCfg conn sess st ->
SpockM conn sess st () -> IO Middleware
<Source>
Run Code Online (Sandbox Code Playgroud)
你可以在这里看到,在它使用但没有类型类约束的源代码中forall:
spock :: forall conn sess st. SpockCfg conn sess st ->
SpockM conn sess st () -> IO Wai.Middleware
spock spockCfg spockAppl =
do connectionPool <-
case poolOrConn of
PCNoDatabase ->
{- ... -}
Run Code Online (Sandbox Code Playgroud)
我对 Haskell 很陌生,并试图理解forall.
首先,忘记存在主义。它们有点麻烦——我个人从不使用该扩展名,只-XGADTs在需要时使用更通用的扩展名。
另外,请允许我使用?符号进行通用量化,我发现它更具可读性。(请注意,它看起来有点像\lambda,它是 的值级类似物?。)这需要-XUnicodeSyntax.
所以,签名
spock :: ? conn sess st. SpockCfg conn sess st -> SpockM conn sess st () -> IO Middleware
Run Code Online (Sandbox Code Playgroud)
对于所有外部目的,与
spock :: SpockCfg conn sess st -> SpockM conn sess st () -> IO Middleware
Run Code Online (Sandbox Code Playgroud)
或者
spock :: SpockCfg c s t -> SpockM c s t () -> IO Middleware
Run Code Online (Sandbox Code Playgroud)
当你看到这样一个带有明确的签名时?,原因通常与-XExistentialQuantification或没有任何关系-XRankNTypes。相反,他们要么只是发现明确说明什么是类型变量会更清楚,要么定义可能会使用-XScopedTypeVariables. 例如,这两个定义实际上是不同的:
{-# LANGUAGE ScopedTypeVariables, UnicodeSyntax #-}
foo :: a -> a
foo x = xAgain
where xAgain :: a
xAgain = x
foo' :: ? a . a -> a
foo' x = xAgain
where xAgain :: a
xAgain = x
Run Code Online (Sandbox Code Playgroud)
foo 不编译,因为全局和局部签名都被解释为隐式量化,即作为
foo :: ? a . a -> a
foo x = xAgain
where xAgain :: ? ? . ?
xAgain = x
Run Code Online (Sandbox Code Playgroud)
但这不起作用,因为现在xAgain必须有一个独立于x您传入的类型的多态类型。相比之下,foo'我们只量化一次,并且a来自全局定义的也是本地使用的类型.
在 的示例中spock,他们甚至不使用作用域类型变量,但我怀疑他们在调试期间使用了,然后就离开了?那里。
| 归档时间: |
|
| 查看次数: |
136 次 |
| 最近记录: |