替代代数数据类型,在记录语法中有很多构造函数
Alternative to algebraic data type with lots of constructors in record syntax
我有一个自定义数据类型来包含景观元素(云、太阳、山脉等)。我需要一个它们的列表,所以我不能使用不同的类型和一个通用的类型类。
它们共享构造函数中的大部分字段,但有些字段具有其他字段所没有的属性(例如,云是否正在下雨)。
截至目前,我有一种具有不同构造函数的数据类型:
data Element = Sun {
elemColorStart :: Color,
elemColorEnd :: Color,
elemCoords :: Coords,
elemPeriod :: Float,
elemSize :: Float,
elemSteps :: Step,
elemTime :: Float
}
| Cloud {
elemKind :: CloudKind,
elemColorMain :: Color,
elemCoords :: Coords,
elemRans :: [Float],
elemSize' :: Size',
elemSteps :: Step,
elemTime :: Float
}
... etc
或者,我可以有一个具有所有可能属性的通用构造函数,如果不需要它们,则不初始化它们,尽管这看起来更糟。
这看起来不太像 "Haskelly",实际上这种方法通常是非常面向对象的。 我做错了什么?欢迎任何其他可能的方法;这不是作业,所以我真的没有任何限制。
将事物隔离成它们自己的数据类型,并使 Element
成为它们的总和:
data Sun = Sun {
colorStart :: Color,
colorEnd :: Color,
coords :: Coords,
period :: Float,
size :: Float,
steps :: Step,
time :: Float
}
data Cloud = Cloud {
kind :: CloudKind,
colorMain :: Color,
coords :: Coords,
rans :: [Float],
size :: Size',
steps :: Step,
time :: Float
}
data Element = SunElement Sun | CloudElement Cloud
现在,您可以拥有专门的 API 来隔离事物,就像关注点分离带来的所有好处一样。
哦,顺便说一句,我已经删除了字段名称的前缀,因为现在我们有了 DuplicateRecordFields
扩展名。
顺便说一句,您会发现 this question 很有用。
Nikita 答案的一个转折点是使用一个名为 Shared
的 ADT 来保存在 Sun
和 Cloud
中找到的字段。如果你愿意,你可以将其与 OO 的继承进行比较。
data Shared = Shared {
coords :: Coords,
steps :: Step,
time :: Float
}
data Sun = Sun {
colorStart :: Color,
colorEnd :: Color,
period :: Float,
size :: Float,
shared :: Shared
}
data Cloud = Cloud {
kind :: CloudKind,
colorMain :: Color,
rans :: [Float],
size :: Size',
shared :: Shared
}
data Element = SunElement Sun | CloudElement Cloud
我有一个自定义数据类型来包含景观元素(云、太阳、山脉等)。我需要一个它们的列表,所以我不能使用不同的类型和一个通用的类型类。
它们共享构造函数中的大部分字段,但有些字段具有其他字段所没有的属性(例如,云是否正在下雨)。
截至目前,我有一种具有不同构造函数的数据类型:
data Element = Sun {
elemColorStart :: Color,
elemColorEnd :: Color,
elemCoords :: Coords,
elemPeriod :: Float,
elemSize :: Float,
elemSteps :: Step,
elemTime :: Float
}
| Cloud {
elemKind :: CloudKind,
elemColorMain :: Color,
elemCoords :: Coords,
elemRans :: [Float],
elemSize' :: Size',
elemSteps :: Step,
elemTime :: Float
}
... etc
或者,我可以有一个具有所有可能属性的通用构造函数,如果不需要它们,则不初始化它们,尽管这看起来更糟。
这看起来不太像 "Haskelly",实际上这种方法通常是非常面向对象的。 我做错了什么?欢迎任何其他可能的方法;这不是作业,所以我真的没有任何限制。
将事物隔离成它们自己的数据类型,并使 Element
成为它们的总和:
data Sun = Sun {
colorStart :: Color,
colorEnd :: Color,
coords :: Coords,
period :: Float,
size :: Float,
steps :: Step,
time :: Float
}
data Cloud = Cloud {
kind :: CloudKind,
colorMain :: Color,
coords :: Coords,
rans :: [Float],
size :: Size',
steps :: Step,
time :: Float
}
data Element = SunElement Sun | CloudElement Cloud
现在,您可以拥有专门的 API 来隔离事物,就像关注点分离带来的所有好处一样。
哦,顺便说一句,我已经删除了字段名称的前缀,因为现在我们有了 DuplicateRecordFields
扩展名。
顺便说一句,您会发现 this question 很有用。
Nikita 答案的一个转折点是使用一个名为 Shared
的 ADT 来保存在 Sun
和 Cloud
中找到的字段。如果你愿意,你可以将其与 OO 的继承进行比较。
data Shared = Shared {
coords :: Coords,
steps :: Step,
time :: Float
}
data Sun = Sun {
colorStart :: Color,
colorEnd :: Color,
period :: Float,
size :: Float,
shared :: Shared
}
data Cloud = Cloud {
kind :: CloudKind,
colorMain :: Color,
rans :: [Float],
size :: Size',
shared :: Shared
}
data Element = SunElement Sun | CloudElement Cloud