我正在阅读"了解你一个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")
我不明白为什么会这样?请解释一下。
答案 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的情况下使用其他字段展开“同事”数据类型。