记录语法字段类型注释仅具有智能构造函数



>我正在尝试创建一个记录,其中一个字段具有未导出的类型,因为它使用的是智能构造函数。使用智能构造函数作为类型不起作用。

 Not in scope: type variable `domain'

也许有一个语言扩展允许我这样做,或者类似的东西?

将构造函数与智能构造函数

一起导出将允许我解决此问题,但这反过来又创造了创建智能构造函数不允许的值的可能性。

我现在拥有的(非工作)代码:

import Domain (domain) -- Domain is not exported, and domain is a smart constructor for Domain
data Rec = Rec
    { dint :: domain Int -- what do I do here? I want it to be `Domain Int` but `Domain` isn't exported.
    ...
    }

这里的问题是类型构造函数和数据构造函数的概念之间的混淆。为简洁起见,我将用一个例子来说明差异。

data Foo a = Bar [a]

在上面的表达式中,Foo 是类型构造函数,Bar 是数据构造函数。主要区别在于Foo是 Haskell 类型空间中的值,Bar是其数据空间中的值。类型空间中的值不能在数据空间中使用,反之亦然。例如,编译器会在以下表达式上出错。

someVariable :: Bar Int
someVariable = Foo [15]

但是,下一个表达式是完全有效的。

someVariable :: Foo Int
someVariable = Bar [15]

此外,所有类型构造函数都必须以大写字母开头。任何以小写字母开头的类型都将被视为类型变量,而不是类型构造函数(上面定义中的a就是一个例子)。

智能构造函数

的引入为这个问题增加了另一层,但要了解的关键是智能构造函数是数据构造函数,而不是类型构造函数。在 Rec 的定义中,您尝试在 dint 字段的类型声明中使用智能构造函数 domain。但是,由于domain是数据构造函数而不是类型构造函数,并且它是小写的,因此 Haskell 编译器尝试将domain解释为类型变量的名称。由于您从未在Rec类型的定义中指定名为 domain 的变量,因此编译器引发了错误。

实际上,您不需要导出数据构造函数来解决问题Domain,只需导出类型本身即可。这可以通过以下方法完成。

module Domain (
    Domain(), domain,
    ...
    ) where

在导出定义中包含Domain()告诉 Haskell 导出 Domain 类型构造函数,但不导出其任何数据构造函数。这样可以使用 safe 构造函数保留所需的安全性,并允许您正确定义类型。现在,您可以在 Rec 的定义中使用新导出的类型。

import Domain (Domain(), domain)
data Rec = Rec
    { dint :: Domain Int
    ...
    }

有关更多信息,我强烈建议您阅读有关构造函数和智能构造函数的 HaskellWiki 文章。

最新更新