当前位置: 首页 > 知识库问答 >
问题:

GHC何时可以推断约束变量?

司马钱明
2023-03-14

我得到类型推断错误,因为GHC不会推断约束变量。一阶统一看起来是不可推论的。在进一步的调查中,我发现插入让绑定改变了类型推断的行为。我想知道GHC在做什么。

这里的代码演示了这个问题。newtypeConstrainedF c代表一个多态函数,其类型参数受c约束。据我所知,GHC不会根据ConstrainedF的值推断c

{-# LANGUAGE RankNTypes, ScopedTypeVariables, ConstraintKinds, MonoLocalBinds #-}

import Data.Monoid
import GHC.Prim(Constraint)

newtype ConstrainedF c =
  ConstrainedF { runConstrainedF :: forall a. c a => [a] -> a}

applyConstrainedF :: forall c a. c a => ConstrainedF c -> [a] -> a
applyConstrainedF f xs = runConstrainedF f xs

-- GHC cannot infer the type parameter of ConstrainedF
foo :: [Int]
foo = applyConstrainedF (ConstrainedF mconcat) [[1], [2]]
--foo = applyConstrainedF (ConstrainedF mconcat :: ConstrainedF Monoid) [[1], [2]]

应该可以推断应用程序中的类型ConstrainedF mconcat

  1. ConstrainedF对于所有c.(对于所有a.c.a.)都有类型=

然而,GHC抱怨:

Could not deduce (Monoid a) arising from a use of `mconcat'
from the context (c0 a).

关于约束变量,我必须遵循哪些规则,以便GHC可以推断类型?

针对模糊类型错误的典型解决方案是添加代理值来约束模糊类型。当我尝试的时候,这很挑剔。如果我只是添加一个额外的参数来约束c的类型,它可以工作:

data Cst1 (c :: * -> Constraint) = Cst1

monoid :: Cst1 Monoid
monoid = Cst1

applyConstrainedF :: forall c a. c a => ConstrainedF c -> Cst1 c -> [a] -> a
applyConstrainedF f _ xs = runConstrainedF f xs

foo :: [Int]
foo = applyConstrainedF (ConstrainedF mconcat) monoid [[1], [2]]

但是在foo中引入let绑定会混淆类型推断,并且它不能再将cMonoid统一起来。

foo_doesn't_work :: [Int]
foo_doesn't_work = let cf = ConstrainedF mconcat
                   in applyConstrainedF cf monoid [[1], [2]]

由于类型推断在这两个函数中的一个函数中得到了正确的答案,这告诉我GHC在某些情况下会统一约束变量,但在其他情况下不会。我不明白发生了什么。


共有1个答案

孙辰阳
2023-03-14

这里的问题是分型。在你的例子中,c也可以是(幺半群b,等式b)

此外,还可以使用数据。可键入以检查c的实例化内容。

或者,如果您要求将(c,d)(一对约束)与幺半群“统一”呢?

你问题第二部分的答案是-你猜对了!-让我们概括一下。

我知道你猜到了,因为你添加了一个monocalbindspragma。然而,它并没有达到你期望的效果。你看,它只会停止真正的局部绑定的泛化——那些依赖于函数参数或其他局部绑定的绑定。

例如,这种方法有效:

foo_does_work :: () -> [Int]
foo_does_work x =
  let cf = const (ConstrainedF mconcat) x
  in applyConstrainedF cf monoid [[1], [2]]

有关详细信息,请参阅Let generalization:哪些绑定受到影响?

 类似资料:
  • 我有一系列复杂的类型级别函数,它们的计算结果如下: 显然,在这种情况下,这个表达式是一个。更一般地说,我们可以说: 有没有办法教GHC推断这一点? 编辑:@chi指出,在某些情况下,GADT可以解决这一问题,但我的特殊情况是: 然后 不能被访问,但是也许GHC应该能够推断出

  • 我定义了一个自定义GADT,其中类型构造函数对类型变量有一个类型类约束,如下所示: 我假设我不必提到约束,因为它是在GADT定义中声明的。我唯一能想到的部分原因是GADT在函数中的位置。我对此不太了解,但据我所知,在中处于正位置,在中处于负位置。 我什么时候必须明确地提到类型类约束,什么时候GHC自己根据GADTs类型构造函数上的约束来解决它?

  • 问题内容: 为什么没有一个 TRUNCATE 上工作?即使我知道了: 错误1701(42000):无法截断在外键约束中引用的表(。,CONSTRAINT FOREIGN KEY()参考。()) 问题答案: 您不能在上面应用FK约束的表(与相同)。 要变通解决此问题,使用这些解决方案之一。两者都存在破坏数据完整性的风险。 选项1: 消除约束 执行 手动删除现在 无处* 引用的行 * 创建约束 选项2

  • 问题内容: 我正在尝试创建一个简单的数据库,其中有一张客户数据表和一张订单数据表。我正在尝试写一个约束,使客户在给定的一天不能订购超过特定数量的商品。这是我所拥有的: 这就是我为强制执行此约束而写的内容,但它不起作用。我认为这是因为ORDER_NUM和ORDER_DATE永远不会有相等的值。 我的问题是如何使这种约束发挥作用,例如如何限制每天的订单量。 问题答案: 由于@ruakh已经清除,因此P

  • 本文向大家介绍Java泛型变量如何添加约束,包括了Java泛型变量如何添加约束的使用技巧和注意事项,需要的朋友参考一下 有时,类或方法需要对类型变量加以约束。下面是一个典型的例子,我们要寻找数组中的最小元素: 上述代码中的限制了用于实例化类型参数T的类型,必须是实现Comparable接口(只含有compareTo方法的标准接口)的类。如果没有对T进行限制,那么无法确保实例化T的类型具有compa

  • 在TypeScript中,我有一个接受带有约束的泛型参数的函数: 现在,我正在尝试这样做,以便您可以选择添加另一个类型作为返回类型的一部分。但是,当我这样做时,我必须为U类型提供一个默认参数。这使得TypeScript停止推断U的值,并使用我提供的默认类型: 所以我的问题是,有没有办法让TypeScript继续从参数推断类型?我不想为U提供默认类型,我总是希望TypeScript推断该值。伪代码,