我可以编译这个类型不明确的函数吗?

Can I get this ambiguoulsly typed function to compile?

首先:我知道我无法使用此功能,除非我启用了 TypeApplications。但我认为 AllowAmbiguousTypes 是为了解决这个问题。

我目前有以下代码:

{-# LANGUAGE ExplicitForAll, AllowAmbiguousTypes #-}

module A where

class B c where
    d :: forall e. e -> c e

class F g where
    h :: forall i. g i -> i

data J k = J {l :: k}

instance B J where
    d = J

instance F J where
    h = l

m :: forall n o. (B n, F n) => o -> o
m = h . d

用 GHCi 8.10.1 解释它或用 GHC 8.10.1 编译它会导致这个错误:

j.hs:20:5: error:
    • Could not deduce (F g0) arising from a use of ‘h’
      from the context: (B n, F n)
        bound by the type signature for:
                   m :: forall (n :: * -> *) o. (B n, F n) => o -> o
        at j.hs:19:1-37
      The type variable ‘g0’ is ambiguous
      These potential instance exist:
        instance F J -- Defined at j.hs:16:10
    • In the first argument of ‘(.)’, namely ‘h’
      In the expression: h . d
      In an equation for ‘m’: m = h . d
   |
20 | m = h . d
   |     ^

j.hs:20:9: error:
    • Could not deduce (B g0) arising from a use of ‘d’
      from the context: (B n, F n)
        bound by the type signature for:
                   m :: forall (n :: * -> *) o. (B n, F n) => o -> o
        at j.hs:19:1-37
      The type variable ‘g0’ is ambiguous
      These potential instance exist:
        instance B J -- Defined at j.hs:13:10
    • In the second argument of ‘(.)’, namely ‘d’
      In the expression: h . d
      In an equation for ‘m’: m = h . d
   |
20 | m = h . d
   |         ^

我的理解是,编译器可能无法将 BF 实例与 dh 的用法联系起来。我认为这样的事情可以解决这个问题:

m @p = h @p . d @p

但是,即使使用TypeApplications,也被拒绝了。

是否有某种语言选项可供我选择,使类似的解决方法成为可能或完全使编译器能够推断出连接?

您的想法是正确的,但是没有现有的方法可以在等式的左侧绑定类型参数。 (正在进行将其添加为扩展的工作,但它已 运行 进入一些需要解决的边缘情况。)但是由于它是带有附加类型签名的顶级定义,您可以只使用那里的类型:

{-# LANGUAGE ScopedTypeVariables, TypeApplications #-}

m :: forall n o. (B n, F n) => o -> o
m = h @n . d @n

使用 the ScopedTypeVariables extension 来引用类型签名中指定的类型 n

为了补充实际答案,您的尝试 (m @p = h @p . d @p) 未通过编译,因为它使用的符号实际上具有完全不相关的含义。

m @p = ... 没有定义带有类型参数 p 的多态函数 m;这种事情没有语法(使用 ScopedTypeVariables 的解决方案是最接近的近似值)。 m@p 是一个 as-pattern,将两个变量 mp 绑定到同一个值。当 @ 的右侧组件是一个非平凡的模式时更常用:

t@(x, y) = somepair

-- equivalent to --

t = somepair
(x, y) = t