haskell - 如何使函数仅可用于 ADT 的某个数据构造函数?

标签 haskell pattern-matching algebraic-data-types maybe undefined-function

我目前正在 Haskell 中使用 ADT,并尝试构建一个 ADT Figure :

data Figure = Rect { x :: Integer, y :: Integer, width :: Integer, height :: Integer}
            | Circle { x :: Integer, y :: Integer, radius :: Integer}
            | CombiFigure Figure Figure
            deriving (Eq, Show, Read)

现在我遇到了如何实现一个不应该接受每个 Figure 的函数的问题。 ,但例如只有一个 Circle .

我已经有一个糟糕的设计了吗?或者是否有一些最佳实践如何做到这一点?

例如,考虑一个直径函数。我想到的所有(我是 Haskell 的完全初学者)是以下两个选项,使用 undefinedMaybe :

1:
diameter :: Figure -> Integer
diameter (Circle _ _ r) = 2 * r
diameter _ = undefined

2:
diameter :: Figure -> Maybe Integer
diameter (Circle _ _ r) = Just (2 * r)
diameter _ = Nothing

有没有更可取的方法来实现这一目标?
谢谢!

最佳答案

你说得对,这里有些不对劲。最好的思考方式是从函数 diameter 开始。并决定理想情况下它的类型应该是什么。你可能会想出

diameter :: Circle -> Integer
diameter (Circle _ _ r) = 2 * r

因为直径只为圆定义。

这意味着您必须通过拆分 Circle(以及 Rect)来扩充数据结构:
data Figure = RectFigure Rect
            | CircleFigure Circle
            | CombiFigure Figure Figure
            deriving (Eq, Show, Read)

data Rect = Rect { rectX :: Integer, rectY :: Integer, rectWidth :: Integer, height :: Integer}
          deriving (Eq, Show, Read)

data Circle = Circle { circleX :: Integer, circleY :: Integer, circleRadius :: Integer}
            deriving (Eq, Show, Read)

这很好,因为它现在更灵活:您可以编写不关心什么的函数 Figure它们适用于,您可以编写在特定 Figure 上定义的函数s。

现在,如果我们在一个更高级的函数中并且有一个对 Figure 的引用。我们想计算它的 diameter如果是 CircleFigure ,那么您可以使用模式匹配来做到这一点。

注意:使用 undefined或异常(在纯代码中)可能是代码异味。它可能可以通过重新考虑您的类型来解决。如果必须指示失败,请使用 Maybe/Either .

关于haskell - 如何使函数仅可用于 ADT 的某个数据构造函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34964015/

相关文章:

c - haskell中的递归数据类型

haskell - 比较 Haskell 的 Snap 和 Yesod Web 框架

MySQL MATCH() AGAINST() 与相反的参数

scala - 使用比较运算符匹配元组

Java 模式和匹配器随机中断

haskell - Haskell 中的子集代数数据类型或类型级别集

rust - 如何证明 Rust 类型系统支持代数数据类型 (ADT)?

haskell - 发现值中使用了哪个 VALUE 构造函数

haskell - 为什么将内置函数应用于被认为是弱头范式的太少参数?

string - 如何将一个字符串拆分为长度全部为 3 的字符串列表?