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过程。