微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

在 Purescript 中使用 ADT 的构造函数作为类型

如何解决在 Purescript 中使用 ADT 的构造函数作为类型

以下是来自 PureScript by Example

的 ADT 示例
data Shape
  = Circle Point Number
  | Rectangle Point Number Number
  | Line Point Point
  | Text Point String

type Point =
  { x :: Number,y :: Number
  }

想做这样的事情有意义吗?

boundingCircle :: Shape -> Circle
boundingBox :: Shape -> Rectangle

目前,这是不允许的,因为 Circle 不是一种类型。我也许可以让 Shape 成为一个类型类,而 Circle、Rectangle 等都有 Shape 的实例。然后我失去了 Shape 是正好 4 个构造函数的并集的语义(模式匹配变得更加混乱)。

将 ADT 构造函数视为类型本身真的值得避免吗?

解决方法

将 ADP 构造函数视为类型是否值得避免是一个毫无意义的问题,因为那是不可能的。 ADT 构造函数不能是类型,这就是结束。

但是,如果您想让 CircleRectangle 作为它们自己的类型可用,但仍然保留 Shape 作为 ADT,那么没有什么不可能:

type Circle = { center :: Point,radius :: Number }

type Rectangle = { center :: Point,width :: Number,height :: Number }

data Shape
  = Circle Circle
  | Rectangle Rectangle
  | Line Point Point
  | Text Point String

boundingCircle :: Shape -> Circle

boundingBox :: Shape -> Rectangle
,

我也许可以让 Shape 成为一个类型类,而 Circle、Rectangle 等 有形状的实例。然后我失去了 Shape 是 恰好 4 个构造函数的并集(模式匹配变得更加混乱)。

实际上您可以同时拥有 4 种独立的类型和简单的模式匹配。

首先是原始示例中与构造函数对应的各个类型:

data Circle = Circle Point Number
data Rectangle = Rectangle Point Number Number
data Line = Line Point Point
data Text = Text Point String

然后 Shape 类型可以是 4 个单独类型的简单“联合”(或“和”):

data Shape = CircleShape Circle | RectangleShape Rectangle | LineShape Line | TextShape Text

这个设置可以让你做你想做的两件事。您提到的函数的形式大致如下:

boundingCircle :: Shape -> Circle
boundingCircle (CircleShape (Circle center radius)) = Circle (...) (...)
boundingCircle (CircleRectangle (Rectangle corner length width)) = Circle (...) (...)

对其余情况依此类推,这也表明您可以对 Shape 进行模式匹配,并知道它是四种特定变体之一。

虽然这不是“免费的胜利”。一切都有利有弊,决定如何设计数据类型并不总是那么简单。特别是,通过上述内容,您会注意到 Shape 上的模式匹配虽然仍然可能,但已经变得更加冗长。很多时候,您实际上并不希望将 Circle 之类的东西作为它们自己的类型。或者您可能对 typeclass 方法感到满意 - 虽然这会阻止您进行模式匹配,但您仍然可以将 boundingCircle 等作为该 typeclass 的方法,或者作为可以轻松从 typeclass 方法派生的其​​他函数.

确实,我建议这里我最喜欢的方法可能正是 typeclass 之一 - 如果您正在设计 typeclass,则可以准确地放入所需的方法,仅此而已。但在这些情况下,从来没有任何“正确答案”——你权衡利弊,做最适合你的用途。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。