Trex简介
Haskell的记录类型是不可扩展的,而一个可扩展的记录类型能添加、删除字段,是一种结构化类型。Trex是一个在Hugs里实现的扩展1,为Haskell添加了可扩展记录类型(后面的记录都是指可扩展记录)。
import Hugs.Trex
p1 :: Rec (x :: Int, y :: Int)
p1 = (x = 1, y = 2)
p2 :: Rec (x :: Int, y :: Int, z :: Int)
p2 = (x = 1, y = 2, z = 9)
p1
和p2
是两个记录,它们都有x
和y
字段,而且p2
还有z
字段。记录的类型的格式是Rec ([字段名::类型])
。因为记录是一种结构化类型,我们可以定义只使用到部分字段的函数:
addPoint2D :: (r1\x, r1\y, r2\x, r2\y)
=> Rec (x :: Int, y :: Int | r1)
-> Rec (x :: Int, y:: Int | r2)
-> Rec (x :: Int, y :: Int)
addPoint2D p1 p2 = (x = #x p1 + #x p2, y = #y p1 +#yp2)
p3 = p1 `addPoint2D` p2
addPoint2D
的类型看起来很复杂,但是它能被推导出来,而且很容易理解。首先r1\x
表示r1
是个记录且里面没有x
字段,Rec (x :: Int, y :: Int | r1)
表示在r1
的基础上加上x
和y
字段。所以addPoint2D
的类型意思是:两个参数都至少有x
和y
字段,返回一个只有x
和y
字段的记录。2
还可以增加、删除字段、改变字段类型:
addZ :: r\z => Rec a -> b -> Rec (z :: b | r)
addZ p v = (z = v | p)
removeZ :: r\z => Rec (z :: b | r) -> Rec r
removeZ (z = _ | p) = p
toStringPoint :: (r\x, r\y, Show a)
=> Rec (x :: a, y :: a | r)
-> Rec (x :: String, y :: String | r)
toStringPoint (x = x, y = y | r) = (x = show x, y = show y | r)
GHC没实现Trex,不过有各种库作为替代:Extensible record↩
这跟Row polymorphism里的表示方法几乎是直接对应的↩