无法使用类型同义词创建对象:type

时间:2015-11-14 15:21:56

标签: haskell

我正在阅读"了解你一个Haskell"在第typeclasses章中,我正在使用此代码:

type EmpData = String
data EmpPair = EmpPair EmpData EmpData deriving (Show)
type Colleagues = EmpPair 
data Team = Team Colleagues deriving (Show)

当我尝试制作Team类型的对象时,ghc给出:

*Main> Team (Colleagues "Ashish" "Ajay")

<interactive>:41:7: Not in scope: data constructor `Colleagues'

然而,这是成功的:

*Main> Team (EmpPair "Ashish" "Ajay")
Team (EmpPair "Ashish" "Ajay")

我不明白为什么会这样?请解释一下。

1 个答案:

答案 0 :(得分:2)

简短的回答是你必须使用类似的东西:

Team (EmpPair "string1" "string2")

Haskell为类型和术语提供了单独的名称空间。这意味着名称可以定义为类型或术语(值或函数)或两者,定义可能相互关联也可能不相关。

在您的代码中,每个名称都是:

data Team = Team Colleagues
      ^       ^       ^-- type
    type     term

type Colleagues = EmpPair
     type-^          ^-- type

data EmpPair = EmpPair EmpData EmpData
   type-^        ^       ^        ^      
               term     type    type

将此与多构造函数类型的示例进行比较:

data Bool = True | False
      ^       ^      ^
    type     term   term

这表示要创建Bool类型的值,我们可以使用函数True或函数False

当一个类型只有一个构造函数时,约定是对类型和构造函数名称使用相同的名称 - 即您的团队类型。 但是,没有理由你必须遵循这一点。您可以决定使用,例如:

data Team = MakeTeam Colleagues

要创建Team类型的值(术语),您的原始定义表示我们需要使用类型为Colleagues的函数Team

Colleagues的定义表示同事类型与EmpPair类型相同。

(类型)EmpPair的定义说,要创建EmpPair类型的值,我们需要使用EmpPair函数和两个EmpData类型的值。

EmpData的定义表明EmpData类型与String类型相同。

总之,我们可以像这样构建一个Team类型的值:

Team (EmpPair "string1" "string2")

您收到错误消息,因为同事不是一个术语 - 它只被定义为一种类型。

<强>更新

要在关于是否应使用PatternSynonyms的评论中回答您的问题,请考虑以下事项:

  • 在Hackage上,PatternSynonyms仅用于约35个软件包(大约8400个)。它不仅没有被广泛使用,而且没有它就可以编写很多有用的代码。

  • 与PatternSynonyms的其他用法相比,您的特定用途非常简单。 PatternSynonyms的大多数用法是创建更精细的抽象层,但在这种情况下,您只是使用它来为构造函数创建备用名称。

  • 您应该问自己是否希望您的用户可以直接访问同事构造函数。如果要隐藏实现细节,最好提供在同事值中创建和访问值的替代方法,例如:

    mkColleagues :: EmpData -> EmpData -> Colleagues
    ...
    
    firstColleague :: Colleagues -> EmpData
    ...
    
    secondColleague :: Colleagues -> EmpData
    ...
    

仅公开这些功能可能会让您在不破坏API的情况下使用其他字段展开“同事”数据类型。