Trex: 可扩展记录

May 17, 2014

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)

p1p2是两个记录,它们都有xy字段,而且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的基础上加上xy字段。所以addPoint2D的类型意思是:两个参数都至少有xy字段,返回一个只有xy字段的记录。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)

  1. GHC没实现Trex,不过有各种库作为替代:Extensible record

  2. 这跟Row polymorphism里的表示方法几乎是直接对应的