Fifth Interlude: Church predecessor function with hibiscus flowers
The technique of rebuilding n and then arranging for one of the rounds to be elided >>205 is not the only way to build predecessor functions. For example the chain of function and argument pairs from the previous interlude >>205 can be built directly on the state transformer and initial state which are the arguments of a Church numeral >>172, instead of being built on succ and zero, thus unwrapping one level of abstraction. We start with the by now usual zero, succ and make-pair, but the first two will only be used to test the predecessor function, not to build it.
(define (zero state-transformer initial-state) initial-state)
(define empty "")
(define (addhibiscus string) (string-append string "πΊ"))
(define (succ n) (lambda (state-transformer initial-state) (state-transformer (n state-transformer initial-state))))
((succ (succ (succ zero))) addhibiscus empty)
=> "πΊπΊπΊ"
(define (make-pair a b) (lambda (receiver) (receiver a b)))
(define (first-projection a b) a)
(define (second-projection a b) b)
(define (first pair) (pair first-projection))
(define (second pair) (pair second-projection))
(first (make-pair "πΊ" "π¦"))
=> "πΊ"
(second (make-pair "πΊ" "π¦"))
=> "π¦"
To obtain the behavior of the Church numeral n-1 we need n-1 applications of the state transformer wrapping the initial state. With n in hand we have n rounds available, so just as in the previous interlude >>205 we use the first round to apply the identity function to the initial state, and then switch to the real state transformer for the remaining rounds.
(define (apply-and-switch-to switch-to-this) (lambda (pair) (make-pair switch-to-this ((first pair) (second pair)))))
(define (identity a) a)
(define (pred n) (lambda (state-transformer initial-state) (second (n (apply-and-switch-to state-transformer) (make-pair identity initial-state)))))
To see pred in action:
((pred zero) addhibiscus empty)
=> ""
((pred (succ zero)) addhibiscus empty)
=> ""
((pred (succ (succ zero))) addhibiscus empty)
=> "πΊ"
((pred (succ (succ (succ zero)))) addhibiscus empty)
=> "πΊπΊ"
((pred (succ (succ (succ (succ zero))))) addhibiscus empty)
=> "πΊπΊπΊ"
((pred (succ (succ (succ (succ (succ zero)))))) addhibiscus empty)
=> "πΊπΊπΊπΊ"
((pred (pred (succ (succ (succ (succ (succ zero))))))) addhibiscus empty)
=> "πΊπΊπΊ"
((pred (pred (pred (succ (succ (succ (succ (succ zero)))))))) addhibiscus empty)
=> "πΊπΊ"
By storing both a function and its argument the pairs are able to simulate both the fake box and the real box from the first interlude >>173, and by being more flexible they don't need two separate definitions to do this.