【问题标题】:Why can't i re-use same value constructor among different data types?为什么我不能在不同的数据类型之间重用相同的值构造函数?
【发布时间】:2018-07-30 15:08:52
【问题描述】:

我是 Haskell 的新手,可能在这里遗漏了一些非常基本的东西,但我无法在不同的数据类型之间重用相同的值构造函数。

data Colour = Red | Pink | Orange | Yellow
data Fruit  = Apple | Orange | Banana

这会产生错误提示

Multiple declarations of ‘Orange’

不知道为什么不允许这样做,我在学习 Haskell 之前一直在使用 OCaml,并且能够定义这样的类型

【问题讨论】:

  • 请注意OrangePink等不是类型;它们是Color(或Fruit)类型的构造函数。
  • 是的,你是对的,很抱歉造成混淆,将其编辑为类型的值构造函数
  • 因为 Haskell 的类型联合是 tagged
  • @WillNess 我不认为这就是原因。原则上,我认为您可以使用类似于 DuplicateRecordFields 的方式来执行此操作,但它还没有被编写。

标签: haskell algebraic-data-types user-defined-data-types value-constructor


【解决方案1】:

作为一个快速练习,尝试定义一种数据类型,然后打开 GHCi 进行检查。

data Colour = Red | Pink | Orange | Yellow

如果你在 GHCi 中使用:t,它会告诉你任何东西的类型。

> :t Red
Red :: Colour
> :t Orange 
Orange :: Colour 

所以这告诉您,您的数据构造函数Orange 实际上只是一个不带参数并产生Colour 类型值的函数。

如果添加重复声明会发生什么?

data Colour = Red | Pink | Orange | Yellow
data Fruit  = Apple | Orange | Banana

现在您已经定义了一个函数Orange,它不接受任何参数并产生Colour 类型的值或Fruit 类型的值。这根本行不通!这与定义您自己的自定义函数 foo 并为其赋予多个类型签名相同:

foo :: Int 
foo :: String
foo = "6"

这显然也不起作用。

要解决这个问题,您可以在其自己的模块中定义每种数据类型,并使用合格的导入来正确确定它们的范围:

import qualified Colour as C -- Module Colour.hs 
import qualified Fruit as F -- Module Fruit.hs 

orange1 = C.Orange :: C.Colour 
orange2 = F.Orange :: F.Fruit

现在,你可能会想“编译器很聪明,它应该知道Orange我在使用它时所说的内容。” 你说对了一部分。正在努力将 Overloaded 或 Duplicate 记录字段引入 Haskell。这里已经定义了类似的各种其他问题,但我会列出一些 供进一步阅读的参考资料。

【讨论】:

  • 感谢您的回答。我有点能够理解它,但仍然不确定为什么存在约束。您证明了无法确定可以理解的 Orange 类型。但是在使用中,我在 Orange 上强制使用类型,这应该是允许的 fruitILike :: Fruit fruitILike = Orange myFavouriteColour :: Color myFavouriteColour = Orange 如果我不'不提供类型签名性质然后确定编译器应该给出错误,但是当指定类型时它应该允许吗?
  • 存在约束是因为编译器假定所有函数都具有单一类型。当您导入合格的,您指定不同的功能。在您的实现中,您在同一个模块中定义了函数Orange 两次,并为其赋予了冲突的类型签名。这有意义吗?
  • 好吧,我想我现在开始了。如果问得不算多,我应该采用什么方法对这些数据进行建模?
  • 是的,数据构造函数也表现得像函数。例如,如果您定义data Fruit = Apple Colour,您将拥有Apple 作为接受Colour 并返回Fruit 的函数
  • 您可以使用OrangeColourOrangeFruit 作为构造函数(即使名称不同),也可以将定义移动到不同的模块。任何一种解决方案都应该适合您!
【解决方案2】:

没有什么特别的原因,这就是语言的设计方式。我认为这个想法是确保编译器可以推断出尽可能多的表达式的类型。请注意,如果语言允许重用构造函数,那么您必须为 show Orange 表达式指定类型 - 编译器无法再推断它。尽管现在很多人并不认真对待这个原因,而且许多现代语言扩展确实破坏了编译器为许多表达式推断类型的能力。所以我想几年后你会发现你的例子已经奏效了:)

【讨论】:

  • 对,所以通过两次声明 Orange 编译器不能自动推断类型,明白了。但是如果我写了一个类型签名并指定了类型(请参阅 jkeuhlen 的答案的评论)那么它应该可以工作,但正如你所说,这是正在处理的事情
猜你喜欢
  • 1970-01-01
  • 2022-01-22
  • 1970-01-01
  • 1970-01-01
  • 2011-06-20
  • 2021-01-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多