答案 0 :(得分:23)
我个人并没有想要限制我创建的数据类型中的类型,但对于我来说,为什么语言设计师“认为允许这是一个坏主意”并不明显。那是为什么?
因为它具有误导性,并且从实际有用的方面完全倒退。
特别是,实际上并没有以您可能期望的方式约束数据类型中的类型。 做了什么做的是对数据构造函数本身放置一个类约束,这意味着你需要在构造一个值时满足该实例......但这就是全部。
因此,例如,你不能简单地定义一个带有Ord
约束的二叉搜索树,然后知道任何树都有可排序的元素;查找和插入函数本身仍然需要Ord
约束。你所要阻止的只是构造一个“包含”某些非有序类型值的空树。就模式匹配而言,根本没有对包含类型的约束。
另一方面,从事Haskell工作的人并不认为合理的版本(人们倾向于假设提供数据类型的上下文)根本就不是一个坏主意!实际上,对数据类型declared with GADT syntax的类约束(广义代数数据类型,在GHC中使用GADTs
语言编译指示启用)确实以明显的方式工作 - 您需要约束构造该值,并且有问题的实例也存储在GADT中,因此您不需要约束来处理值,并且GADT构造函数上的模式匹配允许您使用它捕获的实例。
答案 1 :(得分:8)
在a上添加类型类约束实际上并不是一个坏主意 数据类型 - 它非常有用,并且不会破坏您的其他代码。
糟糕的是,人们通常会期望他们可以 使用数据类型来原谅他们对函数施加约束 使用数据类型,但事实并非如此。 (你可能会认为隐式约束会导致问题。)
对数据类型设置约束实际上将它放在所有构造函数上 提到约束类型。 就像带有约束的普通函数一样,如果使用构造函数, 你必须添加约束。我认为这是健康的,高于一切。
确实确保您无法将数据放入数据类型中,除非您可以这样做 有些事情。它很有用。你不会创建一个编程 通过使用一个失礼,这不是坏习惯,它不是那么可爱 他们想要。
“允许的坏主意”可能是因为GADT确实是他们想要的 如果GADT首先出现,他们就不会这样做。
我认为两者并不是一件坏事。如果你想要一个州 操纵函数,你可以使用你传递的永久显式参数, 或者你可以使用monad并使其隐含。如果你想要约束 数据可以在数据声明或隐式数据声明中使用永久显式数据 与GADT。 GADT和monad更复杂,但它没有 显式参数或数据类型约束错误。