从一对到 lambda 演算/方案中的列表

问题描述

我正在学习一些关于 lambda 演算(非常简洁)的知识,并在如何完成配对的方案中定义了以下内容

; PAIR
; λabf.fab
(define PAIR (lambda (a) (lambda (b) (lambda (f) ((f a) b)))))
(define mypair ((PAIR 1) 2))

; FirsT
; λab.a
(define FirsT (lambda (a) (lambda (b) a)))

; SECOND
; λab.b
(define SECOND (lambda (a) (lambda (b) b)))

(display "First is: ")     (display (mypair FirsT))
(display " | Second is: ") (display (mypair SECOND))
First is: 1 | Second is: 2

如何进一步抽象以创建列表的数据结构,例如,制作类似 [1 2 3 4 5] 而不仅仅是 [2 3] 的东西?

我自己能做的最好的事情就是对这些进行硬编码,例如,五个:

(define five (
    (PAIR 1) (
      (PAIR 2) (
        (PAIR 3) (
          (PAIR 4) 5)))))

(display (five FirsT)) (display ((five SECOND) FirsT)) (display (((five SECOND) SECOND) FirsT)) (display ((((five SECOND) SECOND) SECOND) FirsT)) (display ((((five SECOND) SECOND) SECOND) SECOND))
12345

是否有更“通用”的解决方案?

解决方法

普通 LISP 列表不是 [1 2 3],而是 (1 . (2 . (3 . ())))。它们是用 (cons 1 (cons 2 (cons 3 '()))) 创建的,因此 lambda 演算中的完全相等列表将是 ((PAIR 1) ((PAIR 2) ((PAIR 3) ...)))

现在标准的 lisp 实现通常打印 (1 2 3),但这是打印机完成的一些时髦魔术。它的规则是,如果 cdr 是一个列表,您可以省略点和一组括号。当您使用 lambda 演算对数据建模时,REPL 将始终显示 lambda/闭包对象,因此您需要了解结构并显示相应可视化的实用函数。这不是 lambda 演算的标准,因为它可以满足公理:

(car (cons a b)) ; ==> a
(cdr (cons a b)) ; ==> b

list 是一个辅助函数 cons 链接参数。您确实可以为对创建类似的东西,但它不是 lambda 演算的一部分:

(define TRUE (lambda (p) (lambda (q) p)))
(define NIL (lambda (x) TRUE))

(define (ch-list . args)
  (let helper ((lst (reverse args)) (result NIL))
    (if (null? lst)
        result
        (helper (cdr lst)
                ((PAIR (car lst)) result)))))
,

正如西尔韦斯特所说。列表不是数组,它们是 conses 链,以特殊的 nil() 对象结尾。这意味着要构建这样的东西,您需要 cons 和这个特殊对象。

我在 Racket 中实现了一种名为“oa”(一个参数)的玩具语言,在几分钟前,您可以找到 here。在其最纯粹的变体中,函数的语法是,例如 (λ x x):参数周围没有括号,因为为什么会有?还有 define 可以给事物命名,但仅此而已。下面是这种语言的 conses 实现:

(define true (λ x (λ y x)))
(define false (λ x (λ y y)))

(define cons (λ h (λ t (λ s ((s h) t)))))
(define car (λ l (l true)))
(define cdr (λ l (l false)))
(define nil (λ l true))
(define null? (λ l (l (λ h (λ t false)))))

方便(但也很烦人),oa 使用普通的 Racket 阅读器,因此您可以读取数字,即使它们在语言中没有语义。所以,例如

> (cdr ((cons 1) 1))
1

比如说,制作一个元素的三元素列表:

(define three-elt
  (λ e
    ((cons e)
     ((cons e)
      ((cons e)
       nil)))))
> (three-elt 1)
#<λ>
> (car (three-elt 1))
1
> (cdr (cdr (cdr (three-elt 1))))
{nil}: (λ l true)

(有一些特殊的、片状的、魔法可以让它打印出在最后一种情况下已经defined 的事物的名称。)

给定 zerozero?succpred(后继和前驱)的定义,以及条件函数 cond,看起来像 { {1}},然后您可以编写(((cond test) if-true) if-false) 的脏版本:

nth

这很脏,因为它免费使用 (define nth (λ n (λ c (((cond (zero? n)) (car c)) ((nth (pred n)) (cdr c)))))) ,但您可以使用组合器修复它:我喜欢 U,所以:

nth

其中之一:

(define U
  ;; The U combinator
  (λ f (f f)))

(define nth
  (U (λ t
       (λ n
         (λ c
           (((cond (zero? n))
             (car c))
            (((U t) (pred n)) (cdr c))))))))

我认为你不能做的是这样实现 > ((nth (succ zero)) ((cons true) ((cons false) nil))) {false}: (λ x (λ y y)) > ((nth zero) ((cons true) ((cons false) nil))) {true}: (λ x (λ y x)) ,因为即使你添加了特殊的魔法来表达像 list 这样的 nospread 函数,你已经需要将它的所有参数变成一个列表。但我可能错了。

上述所有函数都存在于oa中的list中。