理解代数数据类型的困难

时间:2016-12-12 10:06:09

标签: haskell data-structures functional-programming algebraic-data-types

我不太确定这个ZInt究竟在描述什么。

data Nat = Zero | S Nat
data ZInt = Z Nat Nat deriving Show

addZ :: ZInt -> ZInt -> ZInt
addZ (Z a b) (Z c d) = Z (add a c) (add b d)

with
add ::  Nat -> Nat -> Nat
add a Zero  = a
add a (S b) = S (add a b)

mult :: Nat -> Nat -> Nat
mult _ Zero  = Zero
mult a (S b) = add a (mult a b)

乍一看,我想也许这是一个复杂数字的表示,添加虚构和实际组件(在函数addZ中)而不显示

的形式
a+b*i

但是这个功能发生了什么?

 subZ :: ZInt -> ZInt -> ZInt 
 subZ (Z a b) (Z c d) = Z (add a d) (add b c)

multZ :: ZInt -> ZInt -> ZInt
multZ (Z a b) (Z c d) = Z (add (mult a d) (mult c b)) (add (mult a c) (mult b d))

所以我确实理解数据Nat = Zero | S nat以及add和mult函数,但不是addZ,subZ和multZ。

2 个答案:

答案 0 :(得分:8)

它只是整数。 Nat代表自然数。 ZInt表示整数。在Z a b if a >= b中,则整数为a - b else - (b - a)。

例如:

ZInt representation | Traditional representation
Z Zero Zero         | 0
Z (S Zero) Zero     | 1
Z Zero (S Zero)     | -1
Z (S Zero) (S Zero) | 0
...

我们可以看到,negate一个整数,只需在其表示中交换Nat值:

negate :: ZInt -> ZInt
negate (Z n m) = Z m n

我们可以像这样定义subZ

a `subZ` b = a `addZ` negate b

此表示不是规范的,Z (S Zero) (S Zero)Z Zero Zero的整数相同。所以,我们可以像这样定义规范形式:

canonical :: ZInt -> ZInt
canonical (Z (S n) (S m)) = canonical (Z n m)
canonical x               = x

通过这种方式定义整数的原因是什么?

首先,它在数学上是清晰的。如果有人定义了名为N的自然数集,我们可以轻松地将名为Z的整数集定义为Z = N * N,其中(*)是两组的乘积。

在Haskell,我只能看到一个原因。通过这种方式,我们可以在类型级别上定义整数。

答案 1 :(得分:4)

首先,ZInt将每个整数表示为有序自然数对。 @freestyle涵盖了这种表示如何运作良好;我将扩展算术运算符如何利用这种编码。

addZsubZmultZ只是在操纵代表每个整数的一对自然数。

addZ (Z a b) (Z c d) = Z (add a c) (add b d)
(a - b) + (c - d) == a - b + c - d
                  == a + c - b - d
                  == (a + c) - (b + d)

subZ (Z a b) (Z c d) = Z (add a d) (add b c)
(a - b) - (c - d) == a - b - c + d
                  == a + d - b - c
                  == (a + d) - (b + c)

multZ (Z a b) (Z c d) = Z (add (mult a d) (mult c b)) (add (mult a c) (mult b d))
(a - b) * (c - d) == ac - ad - bc + bd
                  == ac + bd - ad - bc
                  == (ac + bd) - (ad + bc)

请注意,multZ的给定定义可能会出现错误;它应该是

multZ (Z a b) (Z c d) = Z (add (mult a c) (mult b d)) (add (mult a d) (mult b c))

(为清楚起见,它也应该使用mult b c而不是mult c b,即使自然数的乘法是可交换的。)