gpt4 book ai didi

haskell - 展开 Haskell 数据类型

转载 作者:行者123 更新时间:2023-12-01 08:02:51 24 4
gpt4 key购买 nike

是否可以使用新值扩展数据类型?

例如:以下编译:

data Axes2D = X | Y
data Axes3D = Axes2D | Z

但是,以下内容:

data Axes2D = X | Y deriving (Show, Eq)
data Axes3D = Axes2D | Z deriving (Show, Eq)

type Point2D = (Int, Int)
type Point3D = (Int, Int, Int)

move_along_axis_2D :: Point2D -> Axes2D -> Int -> Point2D
move_along_axis_2D (x, y) axis move | axis == X = (x + move, y)
| otherwise = (x, y + move)

move_along_axis_3D :: Point3D -> Axes3D -> Int -> Point3D
move_along_axis_3D (x, y, z) axis move | axis == X = (x + move, y, z)
| axis == y = (x, y + move, z)
| otherwise = (x, y, z + move)

给出以下编译错误(move_along_axis_3D 注释掉不给出错误):

Prelude> :l expandTypes_test.hs 
[1 of 1] Compiling Main ( expandTypes_test.hs, interpreted )

expandTypes_test.hs:12:50:
Couldn't match expected type `Axes3D' with actual type `Axes2D'
In the second argument of `(==)', namely `X'
In the expression: axis == X
In a stmt of a pattern guard for
an equation for `move_along_axis_3D':
axis == X
Failed, modules loaded: none.

那么是否可以制作 Axes2D 类型的 XY 以及 Axes3D 类型?如果可能的话:我做错了什么?否则:为什么不可能?

最佳答案

连同 Daniel Fischer 所说的,进一步解释为什么这是不可能的:您想要的子类型类型的问题不仅仅是命名歧义;一般来说,它们使类型推断变得更加困难。由于这个原因,我认为 Scala 的类型推断比 Haskell 的类型推断更受限制和局限。

但是,您可以使用类型类系统对此类事物进行建模:

class (Eq t) => HasAxes2D t where
axisX :: t
axisY :: t

class (HasAxes2D t) => HasAxes3D t where
axisZ :: t

data Axes2D = X | Y deriving (Eq, Show)
data Axes3D = TwoD Axes2D | Z deriving (Eq, Show)

instance HasAxes2D Axes2D where
axisX = X
axisY = Y

instance HasAxes2D Axes3D where
axisX = TwoD X
axisY = TwoD Y

instance HasAxes3D Axes3D where
axisZ = Z

然后您可以使用守卫对这些值进行“模式匹配”:

displayAxis :: (HasAxes2D t) => t -> String
displayAxis axis
| axis == axisX = "X"
| axis == axisY = "Y"
| otherwise = "Unknown"

这有许多与子类型相同的缺点:axisXaxisYaxisZ 的使用会变得模棱两可,需要打败练习重点的类型注释。与使用具体类型相比,使用这些类型类约束编写类型签名也有点难看。

还有另一个缺点:对于具体类型,当您编写一个采用Axes2D 的函数时,一旦您处理了XY,您就会知道你已经涵盖了所有可能的值。使用类型类解决方案,没有什么能阻止您将 Z 传递给需要 HasAxes2D 实例的函数。你真正想要的是关系反过来,这样你就可以将 XY 传递给需要 3D 轴的函数,但不能传递 Z 到需要 2D 轴的函数。我认为没有任何方法可以使用 Haskell 的类型类系统对其进行正确建模。

这种技术偶尔有用——例如,将像 GUI 工具包这样的 OOP 库绑定(bind)到 Haskell——但一般来说,使用具体类型并明确支持在 OOP 术语中称为 composition over inheritance 的类型更为自然。 ,即在构造函数中显式包装“子类型”。处理构造函数包装/解包通常不是很麻烦,而且它更灵活。

关于haskell - 展开 Haskell 数据类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8870143/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com