让我们考虑以下代码段:
blah :: a -> b -> a
blah x y = ble x where
ble :: b -> b
ble x = x
这在GHC下编译得很好,这实际上意味着第3行的b
与第一行的b
不同。
我的问题很简单:有没有办法以某种方式将ble
的类型声明与外部上下文中使用的类型相关联,即blah
的类型声明?
显然,这只是一个示例,而不是类型声明的真实用例。
答案 0 :(得分:44)
这可以通过ScopedTypeVariables扩展程序实现。您需要使用显式的forall来将类型变量放入范围。
blah :: forall a b. a -> b -> a
blah x y = ble x where
ble :: b -> b
ble x = x
尝试在启用ScopedTypeVariables的情况下加载此定义会产生:
foo.hs:2:16:
Couldn't match type `a' with `b'
`a' is a rigid type variable bound by
the type signature for blah :: a -> b -> a at foo.hs:2:1
`b' is a rigid type variable bound by
the type signature for blah :: a -> b -> a at foo.hs:2:1
In the first argument of `ble', namely `x'
In the expression: ble x
In an equation for `blah':
blah x y
= ble x
where
ble :: b -> b
ble x = x
您可以告诉GHC将两个b
解释为相同的类型,因为错误表明a
和b
绑定在同一行。
答案 1 :(得分:16)
如果您不想使用ScopedTypeVariables,则可以使用good ole fashion asTypeOf
函数。
-- defined in Prelude
asTypeOf :: a -> a -> a
x `asTypeOf` y = x
blah :: a -> b -> a
blah x y = ble x where
ble x = x `asTypeOf` y
当然,由于类型错误,这将无法编译。
我想指出,有时你可能需要用asTypeOf
来做你想做的事情。采用以下超级使用asTypeOf
的示例,因为我不想考虑实际需要asTypeOf
的案例。对于现实世界的案例,类似的解决方案也是如此。
foo :: Bounded a => Maybe a -> a
foo m = x
where
x = maxBound -- Q: how do I make (x :: a) when given (Maybe a)?
_ = Just x `asTypeof` m -- A: witchcraft!