继续传递类​​型的样式表示

时间:2012-09-25 19:27:16

标签: haskell continuations continuation-passing

假设我们有一个monad,由return(>>=)和一套法律定义。有一种数据类型

newtype C m a = C { unC ∷ forall r. (a → m r) → m r }

也称为CodensityC m a ≅ m a假设mMonad,即我们可以编写两个函数to ∷ Monad m ⇒ m a → C m afrom ∷ Monad m ⇒ C m a → m a

to ∷ Monad m ⇒ m a → C m a
to t = C $ \f → t >>= f

from ∷ Monad m ⇒ C m a → m a
from = ($ return) . unC

并通过等式推理显示to ∘ from ≡ idfrom ∘ to ≡ id,例如:

from . to =                                  -- by definition of `(.)'
  \x → from (to x) =                         -- by definition of `to'
  \x → from (C $ \f → x >>= f) =             -- by definition of `from'
  \x → ($ return) (unC (C $ \f → x >>= f)) = -- unC . C ≡ id
  \x → ($ return) (\f → x >>= f) =           -- β-reduce
  \x → x >>= return =                        -- right identity law
  \x → x =                                   -- by definition of `id'
  id

到目前为止一切顺利。 我的问题是

  • 鉴于一种类型和一堆定律,我们如何构造相应的同构CPS表示?
  • 这种表现形式是独一无二的(我猜不是)?
  • 如果它不是唯一的,那么总是最“简单”(例如的数量:))1?

1 个答案:

答案 0 :(得分:14)

没有这样的编码是唯一的

当你提出问题时,答案显然是“不”

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

哪个编码是最小的......基本类型几乎可以肯定!

密码可能不是您想要的

虽然更多,虽然Codensity令人着迷,但我不相信它与基础类型同构。 from . to = id是容易的方向。

to . from
  = \x -> to (from x)
  = \x -> C $ \f -> (from x) >>= f
  = \x -> C $ \f -> (unC x return) >>= f
  = \(C g) -> C $ \f -> (g return) >>= f

然后你有点卡住了。同样的事情发生在你试图证明a = forall r. (a -> r) -> r但是你被“免费定理”拯救时(如果没有这个,可能有办法做到这一点,但是自由定理使得它很容易)。我知道Codensity没有相应的论据,而且我读过的大多数论文都证明它保留了>>=return,也就是说,如果你只使用monadic构造你的C m a操作以及您拨打to的内容,然后对to . from的调用是身份。

如果我们努力尝试,我们甚至可以提出同构的反例

evil :: C Maybe Int
evil = C $ \h -> case h 1 of
                      Nothing -> h 2
                      Just x  -> Nothing


 to . from $ evil
  = (\(C g) -> C $ \f -> (g return) >>= f) evil
  = C $ \f -> ((\h -> case h 1 of
                      Nothing -> h 2
                      Just x  -> Nothing) return) >>= f
  = C $ \f -> Nothing >>= f

这些也一样吗?

test 1 = Nothing
test n = Just n

unC evil test
  = Just 2
unC (C $ \f -> Nothing >>= f) test
  = Nothing >>= test
  = Nothing

我可能在推导中犯了一个错误。我还没有真正检查过它,但现在我可以说我不认为C m a = m a

另一种CPS

所有数据都可以编码为无类型的lambda函数,这是大约70年前Church发现的一种属性。我们经常谈论“教会编码”数据结构,尽管Oleg建议相反,至少在打字环境中,我们应该谈论“Boehm-Beraducci”编码。无论你怎么称呼它,这个想法都是

(a,b) = forall r. (a -> b -> r) -> r
Either a b = forall r. (a -> r) -> (b -> r) -> r

至少快速而宽松的推理。很明显,这种编码提供了一种将任何 ADT编码为System F类型的方法。这也揭示了一种实现函数式语言的方法:将所有内容视为封闭式内容,并将模式匹配仅作为函数应用程序实现。

实际上,System F甚至有一种将存在类型编码为通用类型的方法

exists a. f a = forall r. (forall a'. f a' -> r) -> r

这是一个非常重要的身份。除此之外,这有助于我们思考更高等级类型的类型推断与存在类型之间的关系。由于类型推断可以判定为2级类型,因此类型推断在具有等级1通用和存在性的系统中也是可判定的。由于存在量化是模块的基础,因此这是重要的事情。