一次更新两个记录字段时的不明确的类型变量(但更新一个时不是!)

时间:2016-01-27 12:23:25

标签: haskell typeclass trifecta

以下代码因“模糊类型变量”错误而失败(底部)。但是,两次更新记录的替代定义很好:这是为什么?此外,下面的“破坏”定义与Trifecta source中的定义非常相似。我正在使用GHC 7.10.3编译三分法1.5.2和解析器0.12.3。

#data-table {
    margin: 20px 0;
}

这是工作(替代)定义

20px

第一个定义产生的错误是:

module Main where

import Text.Trifecta
import Text.Parser.Token.Style as T

-- This definition causes a type error
identStyle :: TokenParsing m => IdentifierStyle m
identStyle =
  T.emptyIdents
    { _styleStart    = letter
    , _styleLetter   = letter
    }

1 个答案:

答案 0 :(得分:4)

哈,这是一个有趣的问题。

这里的问题是emptyIdents是类多态的。因此,当您使用它时,类型推断算法的某些部分必须定义要使用的实例。

当您一次只修改一个字段时,不允许更改记录的类型;也就是说,\record -> record { _styleStart = undefined }的类型是IdentifierStyle m -> IdentifierStyle m。所以通过要求最终类型的

emptyIdents { _styleStart = letter } { _styleLetter = letter }

IdentifierStyle m,我们可以推断第一个emptyIdents也是IdentifierStyle m ,其类型m与参数相同

另一方面,由于记录更新在Haskell中的工作原理,当您一次更新两个字段时(恰好是其类型提及类型参数m的所有字段),更新变为多态。也就是说,\record -> record { _styleStart = undefined, _styleLetter = undefined }的类型是IdentifierStyle m' -> IdentifierStyle m - 注意素数!

因此,如果您同时进行两次更新,例如

emptyIdents { _styleStart = letter, _styleLetter = letter }

然后在IdentifierStyle m修复此更新的最终类型吗 not 确定emptyIdents的类型。

有六种方法可以解决这个问题,但基本的想法是你应该在构建emptyIdents时修复要使用的实例。