Search code examples
lambdaschemelisplambda-calculussicp

From a pair to a list in lambda calculus / scheme


I'm learning a bit about lambda calculus (which is very neat) and have defined the following in scheme for how a pair would be done:

; 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

How would one abstract this further to create a data structure of a list, for example, to make something like [1 2 3 4 5] instead of just [2 3] ?

The best I've been able to do by myself is to sort of hardcode these, for example, for five:

(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

Is there a more 'general' solution for this?


Solution

  • Normal LISP lists are not [1 2 3], they are (1 . (2 . (3 . ()))). They are created with (cons 1 (cons 2 (cons 3 '()))) so the exact equal list in lambda calculus would be ((PAIR 1) ((PAIR 2) ((PAIR 3) ...)))

    Now a standard lisp implementation usually prints (1 2 3), but that is some funky magic done by the printer. Its rule is that if the cdr is a list you can omit the dot and one set of parentheses. When you are using lambda calculus to model data the REPL will always show lambda/closure objects so you need utility functions that understands the structure and displays a visualization that corresponds. This is not par of lambda calculus as for it it is OK to just satisfy the axioms:

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

    list is a auxiliary function that cons chain the arguments. You could indeed make something similar for pairs but it is not a part of lambda calculus:

    (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)))))