这是一个关于受约束的多态值的问题,即:类型的值forall f. cxt f => a
,哪里cxt
是一些约束。
通常,要使用这样的值,我们需要一些具体的约束类型:
data Dict (c :: k -> Constraint) (a :: k) where
Dict :: c a => Dict c a
现在,直接使用这样的值很简单:
runPolymorphicValue :: forall c y b. Dict c y -> (forall a. c a => b) -> b
runPolymorphicValue Dict x = x @y
但是,我在实际调用此函数时遇到了麻烦。
runPolymorphicValueWrapper :: forall c y b. Dict c y -> (forall a. c a => b) -> b
runPolymorphicValueWrapper d x = runPolymorphicValue d x
给出此错误消息:
error:
• Could not deduce: c a0 arising from a use of ‘x’
from the context: c a
bound by a type expected by the context:
forall (a :: k1). c a => b
尽管x
具有所需的类型forall a. c a => b
,但 GHC 似乎已尝试x
在使用时立即单态化,将c a
约束实例化为c a0
for unknown a0
。显然,这失败了。
相比之下,这个定义很好用:
runPolymorphicValue' :: forall c y b. Dict c y -> (forall a. Dict c a -> b) -> b
runPolymorphicValue' Dict f = (f (Dict @c @y))
runPolymorphicValueWrapper' :: forall c y b. Dict c y -> (forall a. Dict c a -> b) -> b
runPolymorphicValueWrapper' d x = runPolymorphicValue' d x
那么,我怎样才能真正调用一个接受类型参数的函数forall f. cxt f => a
呢?
更广泛的背景:
我的最终目标是编写一个函数mapAll
,它将类型(或其他类型)到值* -> a
的映射提升为从类型列表到值列表的映射[*] -> [a]
,即: mapAll :: (All cxt fs) => (forall f. cxt f => a) -> [a]
. 在这里,All cxt fs
意味着这fs
是一些类型的列表,并且cxt f
适用于每个f
类型fs
(请参阅docs)。如果我使用 aforall f. Dict cxt f -> a
而不是 a ,我可以编写这个函数forall f. cxt f => a
。
编辑
看起来 usingforall a. c a => Proxy a -> b
也可以。现在应该可以完成这项工作,但我会留下这个问题。听起来问题确实是过早的单态化。
作为比较,我之前尝试过 using forall a. c a => () -> b
,它给出了与原始示例相同的错误。