8

我正在尝试stack使用定点组合器在 lambda 演算中定义数据结构。我正在尝试定义两个操作,insertion以及removal元素的 sopushpop,但我能够定义的唯一一个操作,即插入,无法正常工作。删除我无法弄清楚如何定义。

这是我的push操作方法,以及我对 a 的定义stack

Stack definition:
STACK = \y.\x.(x y)
PUSH = \s.\e.(s e)

我的堆栈用一个元素初始化以指示底部;我在0这里使用:

stack = STACK 0 = \y.\x.(x y) 0 = \x.(x 0)       // Initialization
stack = PUSH stack 1 = \s.\e.(s e) stack 1 =     // Insertion
    = \e.(stack e) 1 = stack 1 = \x.(x 0) 1 =
    = (1 0)

但是现在,当我尝试插入另一个元素时,它不起作用,因为我的初始结构已被解构。

如何修复STACK定义或PUSH定义,以及如何定义POP操作?我想我必须应用一个组合器来允许递归,但我不知道该怎么做。

参考:http ://en.wikipedia.org/wiki/Combinatory_logic

任何关于 lambda 演算中数据结构定义的进一步解释或示例将不胜感激。

4

2 回答 2

11

通过定义一个组合器,它:

被定义为没有自由变量的 lambda 项,因此根据定义,任何组合子都已经是 lambda 项,

例如,您可以通过以下方式定义列表结构:

Y = (list definition in lambda calculus)
Y LIST = (list definition in lambda calculus) LIST
Y LIST = (element insertion definition in lambda calculus)

直观地说,使用定点组合器,一个可能的定义是——考虑 \ = lambda:

  • 一个列表要么是空的,后跟一个尾随元素,比如0
  • 或者一个列表由一个元素组成x,它可能是前一个列表中的另一个列表。

由于它是使用组合器(定点组合器)定义的,因此无需执行进一步的应用程序,以下抽象本身就是一个 lambda 术语。

Y = \f.\y.\x.f (x y)

现在,将其命名为 LIST:

Y LIST = (*\f*.\y.\x.*f* (x y)) *LIST* -- applying function name
LIST = \y.\x.LIST (x y), and adding the trailing element "0"
LIST = (\y.\x.LIST (x y) ) 0
LIST = (*\y*.\x.LIST (x *y*) ) *0*
LIST = \x.LIST (x 0), which defines the element insertion abstraction.

定点组合Y器,或简单的组合器,允许您考虑 LIST 的定义已经是一个有效的成员,没有自由变量,因此不需要减少。

然后,您可以通过执行以下操作附加/插入元素,例如 1 和 2:

LIST = (\x.LIST (x 0)) 1 2 =
    = (*\x*.LIST (*x* 0)) *1* 2 =
    = (LIST (1 0)) 2 =

但是在这里,我们知道列表的定义,所以我们扩展它:

    = (LIST (1 0)) 2 =
    = ((\y.\x.LIST (x y)) (1 0)) 2 =
    = ((*\y*.\x.LIST (x *y*)) *(1 0)*) 2 =
    = ( \x.LIST (x (1 0)) ) 2 =

现在,插入 elemenet 2

    = ( \x.LIST (x (1 0)) ) 2 =
    = ( *\x*.LIST (*x* (1 0)) ) *2* =
    = LIST (2 (1 0))

由于 LIST 是一个 lambda 术语,使用组合器定义,因此可以在新插入的情况下对其进行扩展,或者简单地保持原样。

为将来的插入扩展:

    = LIST (2 (1 0)) =
    = (\y.\x.LIST (x y)) (2 (1 0)) =
    = (*\y*.\x.LIST (x *y*)) *(2 (1 0))* =
    = \x.LIST (x (2 (1 0))) =
    = ( \x.LIST (x (2 (1 0))) ) (new elements...)

我真的很高兴我能够自己推导出这个,但我很确定在定义堆栈、堆或一些更高级的结构时必须有一些很好的额外条件。

尝试导出堆栈插入/删除的抽象——没有所有的一步一步:

Y = \f.\y.\x.f (x y)
Y STACK 0 = \x.STACK (x 0)
STACK = \x.STACK (x 0)

为了对它执行操作,让我们命名一个空栈——分配一个变量(:

stack = \x.STACK (x 0)

// Insertion -- PUSH STACK VALUE -> STACK
PUSH = \s.\v.(s v)
stack = PUSH stack 1 =
    = ( \s.\v.(s v) ) stack 1 =
    = ( \v.(stack v) ) 1 =
    = ( stack 1 ) = we already know the steps from here, which will give us:
    = \x.STACK (x (1 0))

stack = PUSH stack 2 =
    = ( \s.\v.(s v) ) stack 2 =
    = ( stack 2 ) =
    = \x.STACK x (2 (1 0))

stack = PUSH stack 3 =
    = ( \s.\v.(s v) ) stack 3 =
    = ( stack 3 ) =
    = \x.STACK x (3 (2 (1 0)))

我们再次命名这个结果,以便我们弹出元素:

stack = \x.STACK x (3 (2 (1 0)))

// Removal -- POP STACK -> STACK
POP = \s.(\y.s (y (\t.\b.b)))
stack = POP stack =
    = ( \s.(\y.s y (\t.\b.b)) ) stack =
    = \y.(stack (y (\t.\b.b))) = but we know the exact expansion of "stack", so:
    = \y.((\x.STACK x (3 (2 (1 0))) ) (y (\t.\b.b))) =
    = \y.STACK y (\t.\b.b) (3 (2 (1 0))) = no problem if we rename y to x (:
    = \x.STACK x (\t.\b.b) (3 (2 (1 0))) =
    = \x.STACK x (\t.\b.b) (3 (2 (1 0))) = someone guide me here, if i'm wrong
    = \x.STACK x (\b.b) (2 (1 0)) =
    = \x.STACK x (2) (1 0) =
    = \x.STACK x (2 (1 0))

为了什么,希望我们3弹出了元素。

我试图自己推导出这个,所以,如果我没有遵循 lambda 演算有任何限制,请指出。

于 2012-12-03T08:59:34.107 回答
8

lambda 演算中的堆栈只是一个单链表。单链表有两种形式:

nil  = λz. λf. z
cons = λh. λt. λz. λf. f h (t z f)

这是Church 编码,列表表示为它的catamorphism。重要的是,您根本不需要定点组合器。在此视图中,堆栈(或列表)是一个函数,它为 case 接受一个参数,为nilcase接受一个参数cons。例如,列表[a,b,c]表示如下:

cons a (cons b (cons c nil))

空栈nil相当于KSKI 演算的组合子。构造cons函数是你的push操作。给定一个头部元素h和另一个堆栈t作为尾部,结果是一个新堆栈,该元素h位于最前面。

pop操作只是将列表分成头部和尾部。您可以使用一对功能来做到这一点:

head = λs. λe. s e (λh. λr. h)
tail = λs. λe. s e (λh. λr. r nil cons)

e处理空堆栈的东西在哪里,因为弹出空堆栈是未定义的。这些可以很容易地变成一个返回一对headand的函数tail

pop = λs. λe. s e (λh. λr. λf. f h (r nil cons))

同样,这对是 Church 编码的。一对只是一个高阶函数。该对(a, b)表示为高阶函数λf. f a b。它只是一个函数,给定另一个 function f,适用fab

于 2012-12-27T02:58:22.443 回答