haskell中类型的等价表示(1)–Product

这里我想讨论下一些haskell类型的等价表示。对于一个类型我们可以给出不同的表示。通常我们会使用所谓代数数据结构,但是其实那不是必须的。我们需要的是函数,以及RankNTypes。

 

表示:

通常我们使用data定义一个product如下。

data P a b = P a b

等价的我们可以用一个函数类型来表示‘同样的类型’。

newtype P' a b = P' { unP':: forall r. (a -> b -> r) -> r }

你会问,这两个是等价的吗?下面我们来简单的证明。:)

证明:

先直觉的感受下P’,forall r限制了可能有的实现。为了能返回r,他只可能是下面的形式:

p = \f -> f x y

这里x, y分别是以a, b为类型的常量。

下面我们来推导x, y为什么。

我们加一个helper函数 const和flip:

const :: a -> b -> a
const a _ = a

flip :: (a -> b -> c) -> (b -> a -> c)
flip f b a = f a b

把const和(flip const)作为参数传给p:

p const = const x y = x
p (flip const) = (flip const) x y = y

看到了? :)于是我们得到p的一个递归的表示:

p = \f -> f (p const) (p (flip const))

所以p是由(p const)和(p (filp const))唯一表示的。

现在我们来看P和P’是否有一一对应关系,如果有那就是等价的。

先定义P到P’的映射关系。

toP' :: P a b -> P' a b
toP' (P a b) = P' (\f -> f a b)

P’到P的映射关系如下。

fromP' :: P' a b -> P a b
fromP' (P' p) = P (p const) (p (flip const))

为了证明有一一对应关系,我们需要下面的等式成立:

fromP' . toP' == id
toP' . fromP' == id

fromP’. toP’很容易:

fromP' . toP' (P a b) = P ((\f -> f a b) const) ((\f -> f a b) (flip const)) == P a b

toP’. fromP’需要一点证明:

toP'. fromP' (P' p) = P' (\f -> f (p const) f (p (flip const)))

前面我们说过了,p是由(p const)和(p (filp const))唯一表示的,所以:

P' (\f -> f (p const) f (p (flip const))) == P' p

现在我们可以说两个类型是等价的了。 :)

为什么做这些变换(好处):

可能有人问做了这么多证明,到底我能得到什么好处?这是其实真正我们关心的。

虽然我们说他们是等价的,但是在具体的计算上,他们是有性能差别的。

P a 和 P’a都是functor,但是P’a的fmap会自动的做fuse。

fmap :: (b -> c) -> P' a b -> P' a c
fmap f (P' p) = P' (\g -> p (\a b -> g a (f b)))

fmap f . fmap g == fmap (f . g)

这里f,g会被直接作用到b,省去了代数数据结构的struct和destruct过程。

posted @ 2015-03-23 18:06  wehu  阅读(427)  评论(0编辑  收藏  举报