证明 Haskell 镜头库中声明的类型等效性

Justifying a Type Equivalency Asserted in Haskell Lens Library

根据 tutorial on Lenses:

type Getting b a b  = (b -> Const b b) -> (a -> Const b a)

-- ... equivalent to: (b ->       b  ) -> (a ->       b  )

-- ... equivalent to:                     (a ->       b  )

问题:为什么(b -> b) -> (a -> b)等同于(a -> b)

类型表示 "You give me a b -> b and an a, and I'll give you a b." 具有该类型的函数可以用它的 b -> b 做什么?两个选项:

  1. 完全忽略该函数
  2. 将其应用于 b

如何获得 b 以应用该函数?您使用 a 生成一个。所以无论哪种方式,它都必须完成 a -> b.

的工作

这里有一些代码可以证明(编辑:不完全)同构。

in :: ((b -> b) -> a -> b) -> (a -> b)
in f x = f id x

out :: (a -> b) -> ((b -> b) -> a -> b)
out f g x = g (f x)

教程对此不是很准确。这是 Getting 的完整定义:

type Getting r s a = (a -> Const r a) -> s -> Const r s

剥离 newtype 噪声,

Getting r s a ~= (a -> r) -> s -> r

你应该从中得到的有趣的同构如下:

(forall r. Getting r s a) ~= s -> a

在现已删除的评论中,chi 指出这是 Yoneda lemma.

的特例

同构由

见证
fromGetting :: Getting a s a -> (s -> a)
fromGetting g = getConst . g Const
           -- ~= g id

-- Note that the type of fromGetting is a harmless generalization of
-- fromGetting :: (forall r. Getting r s a) -> (s -> a)

toGetting :: (s -> a) -> Getting r s a
toGetting f g = Const . getConst . g . f
           -- ~= g . f

-- Note that you can read the signature of toGetting as
-- toGetting :: (s -> a) -> (forall r. Getting r s a)

fromGettingtoGetting 都没有 rank-2 类型,但是要 描述 同构, forall 是必不可少的。为什么这是同构?

一方面很简单:忽略 Const 噪声,

  fromGetting (toGetting f)
= toGetting f id
= id . f
= f

另一边比较棘手。

  toGetting (fromGetting f)
= toGetting (f id)
= \g -> toGetting (f id) g
= \g -> g . f id

为什么这等同于 fforall 是这里的关键:

f :: forall r. Getting r s a
  -- forall r. (a -> r) -> s -> r

f 无法生成 r,除非将传递的函数(我们称之为 p)应用于 a 类型的值。除了 ps 类型的值外,它什么也没有给出。所以 f 除了从 s 中提取 a 并将 p 应用于结果之外,实际上什么也做不了。即f p必须"factor"组成两个函数:

f p = p . h

所以

g . f id = g . (id . h) = g . h = f g