直觉类型理论的组合逻辑等效是什么?


87

我最近完成了一门以Haskell和Agda(依赖型函数式编程语言)为特色的大学课程,并且想知道是否有可能用组合逻辑代替lambda微积分。使用Haskell,使用S和K组合器似乎可以实现这一点,从而使其变得毫无意义。我想知道阿格达相当于什么。即,是否可以在不使用任何变量的情况下使等效类型化的函数式编程语言等效于Agda?

另外,是否有可能用合并器代替量化?我不知道这是否是巧合,但是例如通用量化会使类型签名看起来像lambda表达式。有没有办法从类型签名中删除通用量化而不改变其含义?例如:

forall a : Int -> a < 0 -> a + a < a

可以不花大价钱表达同一件事吗?


21
首先找出可能最依赖的K(容易)和S(毛发)类型。抛出Set和Pi的常量,然后尝试重建基本的(不一致的)Set:Set系统是很有趣的。我会再想想,但我有飞机要赶。
猪场工人

Answers:


52

所以我考虑了一下,并取得了一些进展。这Set : Set是以组合方式编码Martin-Löf令人愉快的简单(但不一致)系统的第一步。这不是完成的好方法,但这是最容易上手的地方。这种类型理论的语法只是带有类型注释,Pi类型和Universe集的Lambda微积分。

目标类型理论

为了完整起见,我将介绍规则。上下文有效性仅表示您可以通过邻接居住在Sets的新鲜变量来从空构建上下文。

                     G |- valid   G |- S : Set
--------------     ----------------------------- x fresh for G
  . |- valid         G, x:S |- valid

现在我们可以说如何在任何给定的上下文中综合术语的类型,以及如何根据事物所包含的术语的计算行为来改变某种事物的类型。

  G |- valid             G |- S : Set   G |- T : Pi S \ x:S -> Set
------------------     ---------------------------------------------
  G |- Set : Set         G |- Pi S T : Set

  G |- S : Set   G, x:S |- t : T x         G |- f : Pi S T   G |- s : S
------------------------------------     --------------------------------
  G |- \ x:S -> t : Pi S T                 G |- f s : T s

  G |- valid                  G |- s : S   G |- T : Set
-------------- x:S in G     ----------------------------- S ={beta} T
  G |- x : S                  G |- s : T

与原始版本相比,我做了一个很小的改动,使lambda成为唯一的绑定运算符,因此Pi的第二个参数应该是一个函数,该函数计算返回类型取决于输入的方式。按照惯例(例如,在Agda中,但不幸的是在Haskell中不是),lambda的范围尽可能向右扩展,因此当抽象是高阶运算符的最后一个参数时,您通常可以不加括号:与Pi。您的Agda类型(x : S) -> T变为Pi S \ x:S -> T

Digression。如果您希望能够综合抽象类型,则必须在lambda上添加类型注释。如果您将类型检查转换为操作方式,则仍然需要注释来检查beta-redex (\ x -> t) s,因为您无法我要建议现代设计师检查类型,并从语法中排除beta-redexes。)

离题。该系统不一致,因为Set:Set允许对各种“骗子悖论”进行编码。当马丁·洛夫提出这一理论时,吉拉德在他自己的不一致的系统U中向他发送了对它的编码。我们知道的最近的有毒建筑。)

组合语法和归一化

无论如何,我们有两个额外的符号Pi和Set,所以我们也许可以使用S,K和两个额外的符号来管理组合转换:我为宇宙选择了U,为乘积选择了P。

现在我们可以定义无类型的组合语法(带有自由变量):

data SKUP = S | K | U | P deriving (Show, Eq)

data Unty a
  = C SKUP
  | Unty a :. Unty a
  | V a
  deriving (Functor, Eq)
infixl 4 :.

请注意,我a在此语法中包括了包含由类型表示的自由变量的方法。除了反映自己的意思(每个值得称呼的语法都是带有return嵌入变量和>>=置换替换的免费monad )之外,在转换术语并绑定到其组合形式的过程中,还很容易代表中间阶段。

这是标准化:

norm :: Unty a -> Unty a
norm (f :. a)  = norm f $. a
norm c         = c

($.) :: Unty a -> Unty a -> Unty a        -- requires first arg in normal form
C S :. f :. a $. g  = f $. g $. (a :. g)  -- S f a g = f g (a g)   share environment
C K :. a $. g       = a                   -- K a g = a             drop environment
n $. g              = n :. norm g         -- guarantees output in normal form
infixl 4 $.

(读者的一项工作是为普通形式定义一种类型,并增强这些操作的类型。)

代表类型理论

现在,我们可以为类型理论定义语法。

data Tm a
  = Var a
  | Lam (Tm a) (Tm (Su a))    -- Lam is the only place where binding happens
  | Tm a :$ Tm a
  | Pi (Tm a) (Tm a)          -- the second arg of Pi is a function computing a Set
  | Set
  deriving (Show, Functor)
infixl 4 :$

data Ze
magic :: Ze -> a
magic x = x `seq` error "Tragic!"

data Su a = Ze | Su a deriving (Show, Functor, Eq)

我以Bellegarde和Hook的方式(由Bird和Paterson推广)使用de Bruijn索引表示形式。类型Su a比包含更多元素a,我们将其用作Ze绑定器下的自由变量的类型,将其用作新的绑定变量,并Su x作为旧自由变量的移位表示形式x

将术语翻译成组合词

完成此操作后,我们将基于括号抽象获得通常的翻译。

tm :: Tm a -> Unty a
tm (Var a)    = V a
tm (Lam _ b)  = bra (tm b)
tm (f :$ a)   = tm f :. tm a
tm (Pi a b)   = C P :. tm a :. tm b
tm Set        = C U

bra :: Unty (Su a) -> Unty a               -- binds a variable, building a function
bra (V Ze)      = C S :. C K :. C K        -- the variable itself yields the identity
bra (V (Su x))  = C K :. V x               -- free variables become constants
bra (C c)       = C K :. C c               -- combinators become constant
bra (f :. a)    = C S :. bra f :. bra a    -- S is exactly lifted application

键入组合器

翻译显示了我们使用组合器的方式,这为我们提供了有关它们的类型应有的线索。U并且P只是集合构造函数,因此,编写未翻译的类型并为Pi允许使用“ Agda表示法”,我们应该

U : Set
P : (A : Set) -> (B : (a : A) -> Set) -> Set

K组合子被用于某种类型的值解除A过一些其它类型的常数函数G

  G : Set   A : Set
-------------------------------
  K : (a : A) -> (g : G) -> A

S组合子被用来提升应用超过一个类型,在其上所有的部分可以依赖。

  G : Set
  A : (g : G) -> Set
  B : (g : G) -> (a : A g) -> Set
----------------------------------------------------
  S : (f : (g : G) ->    (a : A g) -> B g a   ) ->
      (a : (g : G) ->    A g                  ) ->
           (g : G) ->    B g (a g)

如果您查看的类型S,您会发现它准确地说明了类型理论的上下文应用规则,这就是使其适合反映应用程序构造的原因。这就是它的工作!

然后我们只申请封闭物品

  f : Pi A B
  a : A
--------------
  f a : B a

但是有一个障碍。我用普通类型理论而不是组合类型理论写了组合器的类型。幸运的是,我有一台可以翻译的机器。

组合式系统

---------
  U : U

---------------------------------------------------------
  P : PU(S(S(KP)(S(S(KP)(SKK))(S(KK)(KU))))(S(KK)(KU)))

  G : U
  A : U
-----------------------------------------
  K : P[A](S(S(KP)(K[G]))(S(KK)(K[A])))

  G : U
  A : P[G](KU)
  B : P[G](S(S(KP)(S(K[A])(SKK)))(S(KK)(KU)))
--------------------------------------------------------------------------------------
  S : P(P[G](S(S(KP)(S(K[A])(SKK)))(S(S(KS)(S(S(KS)(S(KK)(K[B])))(S(KK)(SKK))))
      (S(S(KS)(KK))(KK)))))(S(S(KP)(S(S(KP)(K[G]))(S(S(KS)(S(KK)(K[A])))
      (S(S(KS)(KK))(KK)))))(S(S(KS)(S(S(KS)(S(KK)(KP)))(S(KK)(K[G]))))
      (S(S(KS)(S(S(KS)(S(KK)(KS)))(S(S(KS)(S(S(KS)(S(KK)(KS)))
      (S(S(KS)(S(KK)(KK)))(S(KK)(K[B])))))(S(S(KS)(S(S(KS)(S(KK)(KS)))(S(KK)(KK))))
      (S(KK)(KK))))))(S(S(KS)(S(S(KS)(S(KK)(KS)))(S(S(KS)(S(KK)(KK)))
      (S(S(KS)(KK))(KK)))))(S(S(KS)(S(S(KS)(S(KK)(KS)))(S(KK)(KK))))(S(KK)(KK)))))))

  M : A   B : U
----------------- A ={norm} B
  M : B

因此,在所有难以理解的荣耀中,您都拥有了它Set:Set

还有一个问题。系统的语法使您无法仅凭术语猜测GA和的B参数,S以及类似K的。相应地,我们可以通过算法验证类型派生,但是我们不能像原始系统那样仅对组合器项进行类型检查。可能的工作是要求类型检查器的输入带有有关S和K使用的类型注释,从而有效地记录派生。但这是另一种蠕虫……

如果您足够敏锐地开始,那么这里是个好地方。其余的是“幕后”东西。

生成组合器的类型

我使用括号从相关类型理论术语中提取了这些组合类型。为了说明我是如何做到的,并且使这篇文章并非毫无意义,请允许我提供设备。

我可以编写组合器的类型,对它们的参数进行完全抽象,如下所示。我利用了方便的pil函数,该函数结合了Pi和lambda以避免重复域类型,并且非常有帮助地允许我使用Haskell的函数空间来绑定变量。也许您几乎可以阅读以下内容!

pTy :: Tm a
pTy = fmap magic $
  pil Set $ \ _A -> pil (pil _A $ \ _ -> Set) $ \ _B -> Set

kTy :: Tm a
kTy = fmap magic $
  pil Set $ \ _G -> pil Set $ \ _A -> pil _A $ \ a -> pil _G $ \ g -> _A

sTy :: Tm a
sTy = fmap magic $
  pil Set $ \ _G ->
  pil (pil _G $ \ g -> Set) $ \ _A ->
  pil (pil _G $ \ g -> pil (_A :$ g) $ \ _ -> Set) $ \ _B ->
  pil (pil _G $ \ g -> pil (_A :$ g) $ \ a -> _B :$ g :$ a) $ \ f ->
  pil (pil _G $ \ g -> _A :$ g) $ \ a ->
  pil _G $ \ g -> _B :$ g :$ (a :$ g)

定义好这些内容后,我提取了相关的开放子术语并通过翻译对其进行了处理。

De Bruijn编码工具包

这是建造方法pil。首先,我定义了一类Fin用于变量的ite集合。每个这样的集合emb在上面的集合中都有一个保留构造函数的edding,以及一个新top元素,您可以将它们区分开:embd函数告诉您值是否在的图像中emb

class Fin x where
  top :: Su x
  emb :: x -> Su x
  embd :: Su x -> Maybe x

我们当然可以,实例FinZeSuc

instance Fin Ze where
  top = Ze              -- Ze is the only, so the highest
  emb = magic
  embd _ = Nothing      -- there was nothing to embed

instance Fin x => Fin (Su x) where
  top = Su top          -- the highest is one higher
  emb Ze     = Ze            -- emb preserves Ze
  emb (Su x) = Su (emb x)    -- and Su
  embd Ze      = Just Ze           -- Ze is definitely embedded
  embd (Su x)  = fmap Su (embd x)  -- otherwise, wait and see

现在,我可以使用弱化操作来定义不等值

class (Fin x, Fin y) => Le x y where
  wk :: x -> y

wk函数应将的元素x作为的最大元素嵌入y,以使其中的多余内容y较小,从而以de Bruijn索引而言,绑定范围更广。

instance Fin y => Le Ze y where
  wk = magic    -- nothing to embed

instance Le x y => Le (Su x) (Su y) where
  wk x = case embd x of
    Nothing  -> top          -- top maps to top
    Just y   -> emb (wk y)   -- embedded gets weakened and embedded

一旦您解决了这些问题,剩下的工作就由排名靠前的n位行凶手完成。

lam :: forall x. Tm x -> ((forall y. Le (Su x) y => Tm y) -> Tm (Su x)) -> Tm x
lam s f = Lam s (f (Var (wk (Ze :: Su x))))
pil :: forall x. Tm x -> ((forall y . Le (Su x) y => Tm y) -> Tm (Su x)) -> Tm x
pil s f = Pi s (lam s f)

高阶函数不仅为您提供表示变量的术语,还为您提供了重载的东西,它在任何可见变量的范围内都可以正确表示该变量。就是说,我麻烦按类型区分不同的范围这一事实为Haskell typechecker提供了足够的信息来计算转换为de Bruijn表示形式所需的移位。为什么要养狗并自己吠叫?


这可能是非常愚蠢的,但是如果添加F组合器,此图片将如何变化?F根据其第一个参数的不同,其行为也不同:如果A是原子,M并且N是项且PQ是一个复合,则FAMN -> MF(PQ)MN -> NPQ。这不能用SK(I)微积分表示,但K可以表示为FF。这样可以扩展您的无积分MLTT吗?
kram1032 '16

我很确定这个括号抽象过程存在问题,特别是“组合器变为常数”部分,对于组合器c∈{S,K,U,P},它会将λx.c转换为Kc。问题在于这些组合器是多态的,并且可能以依赖于x的类型使用。此类翻译无法保留此类型。举一个具体的例子,λ (A : Set) → λ (a : A) → a类型术语(A : Set) → (a : A) → A被翻译为S(S(KS)(KK))(KK),不能用于第二个参数的类型取决于第一个参数的类型。
安德斯·卡塞格

8

我猜在某些情况下,“括号抽象”也适用于依赖类型。在以下论文的第5节中,您会找到一些K和S类型:

令人毛骨悚然但有意义的巧合
依赖类型安全的语法和评估
Conor McBride,斯特拉斯克莱德大学,2010年

将lambda表达式转换为组合表达式大致相当于将自然演绎证明转换为Hilbert样式证明。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.