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

Mar*_*ger 5 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)
Run Code Online (Sandbox Code Playgroud)

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

我的设计已经不好了吗?或者有一些最佳实践如何做到这一点?

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

1:

diameter :: Figure -> Integer
diameter (Circle _ _ r) = 2 * r
diameter _ = undefined
Run Code Online (Sandbox Code Playgroud)

2:

diameter :: Figure -> Maybe Integer
diameter (Circle _ _ r) = Just (2 * r)
diameter _ = Nothing
Run Code Online (Sandbox Code Playgroud)

是否有更好的方法来实现这一目标?谢谢!

Wil*_*ell 4

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

diameter :: Circle -> Integer
diameter (Circle _ _ r) = 2 * r
Run Code Online (Sandbox Code Playgroud)

因为直径仅针对圆定义。

这意味着您必须通过拆分 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)
Run Code Online (Sandbox Code Playgroud)

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

现在,如果我们在一个更高层的函数中并且有一个对 a 的引用Figure,并且我们想要计算它diameter (如果它是 a )CircleFigure,那么您可以使用模式匹配来执行此操作。

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