Haskell如何确定正确的数据构造函数?

时间:2014-03-08 18:06:11

标签: haskell

这是我的代码:

data TC a = DC1 a | DC2 a

getDC           :: TC a -> String  
getDC (DC1 x)   = "created by first data constructor"  
getDC (DC2 x)   = "created by second data constructor"  

在拥抱中:

Main> getDC (DC1 10)

“由第一个数据构造函数”

创建
Main> getDC (DC2 10)

“由第二个数据构造函数”

创建

因此,解释器可以确定使用哪个数据构造函数。 据我所知,每个值都有一个相关的类型。我们来看看:


Main> :t (DC1 10)

DC1 10 :: Num a => TC a

Main> :t (DC2 10)  

DC2 10 :: Num a => TC a


只能在那里看到类型构造函数(TC)。

解释器为什么,在何处以及如何保存有关数据构造函数的其他信息?

2 个答案:

答案 0 :(得分:6)

虽然类型提供了重要的编译时信息,但您仍然在运行时操作值。使用的构造函数只是值的属性 - 特别是,您使用模式匹配来确定值中使用的构造函数的选择。

getDC           :: TC a -> String  
getDC (DC1 x)   = "created by first data constructor"  
getDC (DC2 x)   = "created by second data constructor"

-- or, to be more clear about the pattern matching

getDC           :: TC a -> String  
getDC dc = case dc of
  (DC1 x) -> "created by first data constructor"  
  (DC2 x) -> "created by second data constructor"

为了更加清晰,让我们尝试制作自然数而不是使用抽象的TC类型。

data Nat = Zero | Succ Nat

换句话说,我们写为0的内容可以表示为Nat

Zero :: Nat

我们写为3的内容可以表示为

Succ (Succ (Succ Zero))

我们可以在`Nat

上写一个函数
isThree :: Nat -> Bool
isThree (Succ (Succ (Succ Zero))) = True
isThree _                         = False

并且此类型的行为未在其类型(Nat -> Bool)中指示,因此必须由该值执行该行为。实际上,我们使用模式匹配来破坏价值并强制执行行为。

答案 1 :(得分:4)

将值视为包含标记字段的框,该字段标识用于创建它的数据构造函数,以及该构造函数所需的其他参数。由于Haskell是静态类型的,因此运行时不必区分不同类型的值,因此标记只需要标识该类型中的数据构造函数。您只能通过模式匹配间接检查标记,但知道类型和标记,您可以确定数据构造函数,并可以安全地访问参数。

注意,如果类型只有一个数据构造函数,那么该类型的值不需要标记。