类型应用程序和约束种类

时间:2016-08-27 20:42:57

标签: haskell

(我并不完全熟悉Haskell的约束求解器的内部工作原理,所以这可能是一个新手问题。)

尝试在GHC 8.0.1上使用类型应用程序时,如以下示例代码所示

{-# LANGUAGE KindSignatures, RankNTypes, ConstraintKinds, ScopedTypeVariables, TypeApplications #-}
module Test where

import Data.Constraint

test0 :: forall (b :: *) . (forall a . a -> Bool) -> b -> Bool
test0 g = g @b

test1 :: forall (c :: * -> Constraint) (b :: *) . (c b) => (forall a . c a => a -> Bool) -> b -> Bool
test1 g = g @b

它给了我以下错误

• Could not deduce: c0 b
  from the context: c b
    bound by the type signature for:
               test1 :: c b => (forall a. c a => a -> Bool) -> b -> Bool
    at Test.hs:9:10-101
• In the ambiguity check for ‘test1’
  To defer the ambiguity check to use sites, enable AllowAmbiguousTypes
  In the type signature:
    test1 :: forall (c :: * -> Constraint) (b :: *).
             (c b) => (forall a. c a => a -> Bool) -> b -> Bool

• Could not deduce: c a
  from the context: c b
    bound by the type signature for:
               test1 :: c b => (forall a. c a => a -> Bool) -> b -> Bool
    at Test.hs:9:10-101
  or from: c0 a
    bound by the type signature for:
               test1 :: c0 a => a -> Bool
    at Test.hs:9:10-101
• In the ambiguity check for ‘test1’
  To defer the ambiguity check to use sites, enable AllowAmbiguousTypes
  In the type signature:
    test1 :: forall (c :: * -> Constraint) (b :: *).
             (c b) => (forall a. c a => a -> Bool) -> b -> Bool

test0适用于没有涉及约束的地方,但test1没有。

1 个答案:

答案 0 :(得分:6)

如果您启用了TypeApplications,则还应启用AllowAmbiguousTypes。如果这样做,错误就会消失。

ambiguity check拒绝定义t,因此任何t :: type注释都无法进行类型检查。例如:

test1 :: Show a => Int
test1 = 0

如果我们尝试在我们的计划中的其他地方使用test1,我们发现无法通过Show a注释来解决::约束。因此,歧义检查拒绝定义本身。

当然,对于类型应用程序,歧义检查变得毫无意义(可以说,在这种情况下默认情况下应该关闭它),因为test1 @type很好并且只要有Show type实例就完全确定可用。

请注意,这与着名的show . read歧义不同。这仍然会产生错误,AllowAmbiguousTypes也是如此:

test2 = show . read 
-- "ambiguous type variable prevents the constraint from being solved"

在操作上,c => t类型的值只是从c - 类型实例到t的函数。只定义test1很好,因为我们总是可以定义一个常量函数。但是,在show . read中我们需要提供实例作为参数(否则没有代码可以运行),并且无法解决它们。在没有类型应用程序的情况下使用test1同样不明确。