我们可以在 Haskell 中证明的类型

Types we can prove things about in Haskell

我们可以证明 Haskell 中涉及本机类型的同构吗?

import Prelude

newtype Leibniz a b = Leibniz {unLeibniz :: forall f. f a -> f b}


data One = One

-- `u` and `v` are inverse
u :: Bool -> Either One One
u b = if b then Right One else Left One

v :: Either One One -> Bool
v = \case
  (Left _) -> False
  (Right _) -> True

--- Can we prove proof that ?
p :: Leibniz Bool (Either One One)
p = Leibniz (\(x :: f Bool) -> __ :: f (Either One One))

我相信没有Leibniz Bool (Either One One)类型的好词。确实,有些“奇怪的”fs 我们无法进行这种转换;简单的例子是 Bool :~: Bool 是有人居住的,但 Bool :~: Either One One 不是,所以如果 f = (:~:) Bool 那么就没有 f Bool -> f (Either One One).

类型的函数

但是如果你稍微修改 Leibniz

newtype Leibniz a b = Leibniz {unLeibniz :: forall f. IsoFunctor f => f a -> f b}

这里,IsoFunctor 是一个新的 class,类似于 Functor,只是它要求在两个方向上进行纯映射:

class IsoFunctor f where isomap :: (a -> b) -> (b -> a) -> f a -> f b

这 class 排除了其参数是名义的而不是表示的类型,例如 (:~:) Bool。 (并且,在另一个方向上,总是可以为具有正确种类并且在其参数中具有代表性的类型编写实例。)然后我们可以写:

p :: Leibniz Bool (Either One One)
p = Leibniz (isomap u v)

不幸的是,编译器不(通常也不能)保证 uv 是相反的。