4

这是一个关于受约束的多态值的问题,即:类型的值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 a0for 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,它给出了与原始示例相同的错误。

4

0 回答 0