```
(define atom?
(λ (x)
(and (not (pair? x))
(not (null? x)))))
#+end_src
In theory we could define other things as numbers, for example church numerals.
#+NAME: defonep
#+BEGIN_SRC scheme :noweb yes :results none :exports code :eval never-export
(define one?
(λ (x)
(= x 1)))
#+end_src
#+NAME: defpick
#+BEGIN_SRC scheme :noweb yes :results none :exports code :eval never-export
(define pick
(λ (n lat)
(cond
[(one? n) (car lat)]
[else
(pick (- n 1) (cdr lat))])))
#+end_src
** Y-combinator
In the first book the Y-combinator was derived. It is again:
#+NAME: y-combinator-def
#+begin_src scheme :noweb yes :results none :exports code :eval never-export :language guile
(define Y
(λ (proc)
((λ (f) (f f))
(λ (f)
(proc
(λ (x) ((f f) x)))))))
#+end_src
** All prerequisites :noexport:
#+NAME: prereq
#+BEGIN_SRC scheme :noweb yes :results none :exports none :eval never-export
<<defatom>>
<<defonep>>
<<defpick>>
<<y-combinator-def>>
```

`length`

function using `Y`

<>

(define length (Y (λ (length) (λ (lst) (cond [(null? lst) 0] [else (+ (length (cdr lst)) 1)])))))

The length function is injected as an argument. Thus the expression is not referring to itself, but only ever to its argument.

The inner part looks just like the usual recursive length function. It is using an argument (`length`

) as the thing it calls in the recursive case though.

<>

(simple-format #t "(length '(a b c d)) = ~a\n" (length '(a b c d)))

(length '(a b c d)) = 4

`multirember`

(remove member multiple times) function using `Y`

The argument of `Y`

is always a lambda expression, which takes as argument the function to be called in the recursive case. That function itself returns a function, which takes the actual input. In this example that is a list of atoms.

<>

(define multirember (λ (a lat) ((Y (λ (mr) (λ (lat) (cond [(null? lat) '()] [(eq? a (car lat)) (mr (cdr lat))] [else (cons (car lat) (mr (cdr lat)))])))) lat)))

(multirember 'a '(a b c a d))

<>

(simple-format #t "~a\n" (multirember 'a '(a b c a d)))

(b c d)

`letrec`

`letrec`

offers a way to avoid using `Y`

and possibly get a more easily understandable definition of recursive functions.

`multirember`

(remove member multiple times) function using `letrec`

The following definition of `multirember`

makes use of `letrec`

instead of `Y`

, because the definition of `mr`

inside makes use of `mr`

recursively itself. A normal `let`

would not work here. The recursive `mr`

is then returned and applied to `lat`

, a list of atoms. This chapter introduces `letrec`

.

(define multirember (λ (a lat) ((letrec ([mr (λ (lat) (cond [(null? lat) '()] [(eq? a (car lat)) (mr (cdr lat))] [else (cons (car lat) (mr (cdr lat)))]))]) mr) lat)))

(multirember 'a '(a b c a d))

<>

(simple-format #t "~a\n" (multirember 'a '(a b c a d)))

(b c d)

Using the following definition, one can avoid 1 wrapping of parentheses of the `letrec`

expression and move it into the value part of the `letrec`

expression:

(define multirember (λ (a lat) (letrec ([mr (λ (lat) (cond [(null? lat) '()] [(eq? a (car lat)) (mr (cdr lat))] [else (cons (car lat) (mr (cdr lat)))]))]) (mr lat))))

This seems a bit more readable to me.

`multirember`

with configurable `test?`

predicateWe can use 1 layer of currying to make a "factory" of `multirember`

functions, which know how to test for whether an element should be removed from a list.

(define make-multirember (λ (test?) (λ (a lat) (letrec ([mr (λ (lat) (cond [(null? lat) '()] [(test? a (car lat)) (mr (cdr lat))] [else (cons (car lat) (mr (cdr lat)))]))]) (mr lat)))))

(simple-format #t "~a\n" ((make-multirember =) 1 '(2 4 6 12 1 2)))

(2 4 6 12 2)

(define member? member)

(define union (λ (set1 set2) (cond [(null? set1) set2] [(member? (car set1) set2) (union (cdr set1) set2)] [else (cons (car set1) (union (cdr set1) set2))])))

(simple-format #t "~a\n" (union '(a b c d) '(s b a e)))

(c d s b a e)

`set2`

The text has objections about the fact, that `union`

is always called with 2 arguments, the 2 sets to build the union of, although `set2`

never changes. It argues, that one can make the recursive calls simpler, by capturing `set2`

outside of the recursive part.

(define member? member)

(define union (λ (set1 set2) (letrec ([U (λ (set1°) (cond [(null? set1°) set2] [(member? (car set1°) set2) (U (cdr set1°))] [else (cons (car set1°) (U (cdr set1°)))]))]) (U set1))))

(simple-format #t "~a\n" (union '(a b c d) '(s b a e)))

(c d s b a e)

`member?`

The text also notes, that `union`

relies on `member?`

, which is implemented elsewhere. `union`

serves as an example. `member?`

or `member`

is usually implemented in Scheme dialects, so it will not suddenly change. However, if it were a function, which were to change for example the order of its arguments, then we would have to adapt `union`

and all other functions depending on `member?`

as well. For this reason, the text argues for internalizing the definition of `member?`

inside of `union`

.

(define union (λ (set1 set2) (letrec ([U (λ (set1°) (cond [(null? set1°) set2] [(member? (car set1°) set2) (U (cdr set1°))] [else (cons (car set1°) (U (cdr set1°)))]))] [member? (λ (elem lst) (letrec ([M? (λ (lst°) (cond [(null? lst°) #f] [(eq? elem (car lst°)) #t] [else (M? (cdr lst°))]))]) (M? lst)))]) (U set1))))

(simple-format #t "~a\n" (union '(a b c d) '(s b a e)))

(c d s b a e)

Maybe instead of defining a whole `member?`

inside `letrec`

one could make a minimalistic wrapper for the `member`

function already defined in Scheme. This way we would not reimplement things which are already in our language:

(define union (λ (set1 set2) (letrec ([U (λ (set1°) (cond [(null? set1°) set2] [(member? (car set1°) set2) (U (cdr set1°))] [else (cons (car set1°) (U (cdr set1°)))]))] [member? (λ (elem lst) (letrec ([M? (λ (lst°) (not (null? (member elem lst))))]) (M? lst)))]) (U set1))))

(simple-format #t "~a\n" (union '(a b c d) '(s b a e)))

The book has a bootstrapping approach, so it opts to implement `member?`

inside `union`

. A disadvantage of that is, that it cannot be separately unit-tested. Perhaps the philosophy there is, that encapsulation is more important than tests.