下面的haskell代码编译,好的。
data Point = Point Float Float
data Radius = Radius Float
data Shape = Circle Point Radius
是否可以根据以下代码编写内容(代码编译失败):
data LengthQty = Radius Float | Length Float | Width Float
data Shape = Circle Point Radius
这种尝试背后的想法是半径,长度和宽度代表物理量长度。
请注意,如果写成
,则在第二部分第二行data Shape = Circle Point LengthQty
然后,它编译,但在这种情况下,“LengthQty”可以是像Length,Width或Radius这样的任何东西,只需要Radius。
(1)第二部分有什么问题?
(2)如何纠正实施物理量长度(LengthQty)的想法?
答案 0 :(得分:2)
您的代码无法编译的原因是数据声明的右侧必须是构造函数,后跟 types 列表,即表格
data {-type-} = {-constructor-} {-type-} ... {-type-}
在您的示例中,定义
时data LengthQty = Radius Float | Length Float | Width Float
您已将LengthQty
设为类型,而Radius
,Length
和Width
是构造函数。因此,当你写
data Shape = Circle Point Radius
编译器会看到
形式的内容data {-type-} = {-constructor-} {-type-} {-constructor-}
即。它看到一个构造函数,它期望一个类型,所以它会抛出一个错误。在原始代码中,符号Radius
用于构造函数和类型。当编译器看到
data Shape = Circle Point Radius
它知道此上下文中的Radius
必须是一个类型,因此不可能与构造函数半径混淆。
考虑到这一点,如果你只是写
,你可以正确编译你的代码data Shape = Circle Point LengthQty
您可以使用
获取圆圈的特定实例circle :: Shape
circle = Circle (Point 0 0) (Radius 1)
答案 1 :(得分:2)
编译:
data Point = Point Float Float
data Radius = Radius Float
data Shape = Circle Point Radius
data LengthQty = R Float | Length Float | Width Float
Radius
是类型的名称,也是Float -> Radius
类型的数据构造函数的名称; R
是Float -> LengthQty
类型的数据构造函数。您不能拥有两个具有相同名称的不同数据构造函数。 名称 Radius
已被。
以下也有效:
data LengthQty = R Radius | Length Float | Width Float
如果没有R
,Radius
本身就是:: LengthQty
类型的数据构造函数,它将再次与Radius :: Float -> Radius
冲突。
答案 2 :(得分:0)
之间的有用区别
data Point = Point Float Float
data Radius = Radius Float
data Shape = Circle Point Radius
和
data LengthQty = Radius Float | Length Float | Width Float
是Haskell的类型系统处理它们的方式。 Haskell有一个强大的类型系统,它确保函数传递它可以处理的数据。您编写像LengthQuantity
这样的定义的原因是,如果您有一个可以使用Radius
,Length
或Width
的函数,那么您的函数就不能做。
如果确实有一个可能需要Radius
,Length
或Width
的功能,我会写下这样的类型:
data Point = Point Float Float
data Radius = Radius Float
data Shape = Circle Point Radius
data LengthQty = R Radius
| L Length
| W Width
这样,只能从更具体的类型检查中获益Radius
的函数。