haskell - LYAH - 制作我们自己的类型和我们的类型类

时间:2012-07-19 17:41:14

标签: haskell types typeclass

下面的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)的想法?

3 个答案:

答案 0 :(得分:2)

您的代码无法编译的原因是数据声明的右侧必须是构造函数,后跟 types 列表,即表格

data {-type-} = {-constructor-} {-type-} ... {-type-}

在您的示例中,定义

data LengthQty = Radius Float | Length Float | Width Float 

您已将LengthQty设为类型,而RadiusLengthWidth构造函数。因此,当你写

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类型的数据构造函数的名称; RFloat -> LengthQty类型的数据构造函数。您不能拥有两个具有相同名称的不同数据构造函数。 名称 Radius 已被

以下也有效:

data LengthQty = R Radius | Length Float | Width Float 

如果没有RRadius本身就是:: 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这样的定义的原因是,如果您有一个可以使用RadiusLengthWidth的函数,那么您的函数就不能做。

如果确实有一个可能需要RadiusLengthWidth的功能,我会写下这样的类型:

data Point = Point Float Float  
data Radius = Radius Float  
data Shape = Circle Point Radius

data LengthQty = R Radius
               | L Length 
               | W Width

这样,只能从更具体的类型检查中获益Radius的函数。