2025-11-11 published
;; Higher-order functions
;;;;;;;;;;;;;;;;;;;;;;;;;
; Quotation does not work for our purposes...
(define p '(+ 4 5 6)) ; => '(+ 4 5 6)
(define t '(* 1 2 3)) ; => '(* 1 2 3)
; ... we must use list instead of ' to let + and * symbols evaluate to
; procedures.
(define p (list + 4 5 6)) ; => '(#<procedure:+> 4 5 6)
(define t (list * 1 2 3)) ; => '(#<procedure:*> 1 2 3)
; Define a procedure that applies first element to the rest of the
; elements:
(define (exe li)
(apply (car li) (cdr li)))
(exe (list + 4 5 6)) ; => 15
(exe (list * 1 2 3)) ; => 6
; exe also works for the defined variables:
(exe p) ; => 15
(exe t) ; => 6
; We can use map to apply some function to multiple lists.
(map (car p) (cdr p) (cdr t)) ; => '(5 7 9)
(map (car t) (cdr p) (cdr t)) ; => '(4 10 18)
; cons creates a list from an element and the rest of the list
(cons (car t) (cdr p)) ; => '(#<procedure:*> 4 5 6)
(cons (car p) (cdr t)) ; => '(#<procedure:+> 1 2 3)
; We can combine all together
(exe (cons (car t) ; 1.
(map (car p) ; 2.
(cdr p) (cdr t)))) ; 3.
; (1) Join #<procedure:*> with a list created by
; (2) applying #<procedure:+> to the elements of
; (3) '(4 5 6) and '(1 2 3). Execute.
(exe (cons (car p)
(map (car t)
(cdr p) (cdr t))))
;; Postfix notation with higher-order functions
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(list 6 5 4 +) ; => '(4 5 6 #<procedure:+>)
(list 3 2 1 *) ; => '(1 2 3 #<procedure:*>)
; We create rlist -- reverse list and rexe -- exe that first rlist
; given list.
(define (rlist li)
(define (rev from to)
(if (null? from)
to
(rev (cdr from) (cons (car from) to))))
(rev li '()))
(define (rexe li)
(exe (rlist li)))
(rexe (list 6 5 4 +)) ; => 15
(rexe (list 3 2 1 *)) ; => 6
; We do not need new syntax when we can let arguments be evaluated.
(define (rexe . li)
(exe (rlist li)))
(rexe 6 5 4 +) ; => 15
(rexe 3 2 1 *) ; => 6
;; New syntax needed
;;;;;;;;;;;;;;;;;;;;
(define A 3)
(define B 4)
; String is evaluated to a string so if works as expected.
(if (< A B)
"B is greater."
"A is greater.")
; display returns unspecified value and has side-effect; if works as
; expected.
(if (< A B)
(display "B is greater.")
(display "A is greater."))
; We want nif -- if that works with negated condition. Can it be a
; function?
(define (nif predicate then otherwise)
(if (not predicate)
then
otherwise))
(nif (< A B)
"Not B is greater."
"Not A is greater.")
; It looks it works, but...
(nif (< A B)
(display "Not B is greater.")
(display "Not A is greater."))
; ... it does not. nif arguments are eager evaluated -- bad for
; procedures with side-effects.
(define-syntax nif
(syntax-rules ()
((nif predicate then otherwise)
(if (not predicate)
then
otherwise))))
; Finally, with new syntax, both work as expected.
(nif (< A B)
"Not B is greater."
"Not A is greater.")
(nif (< A B)
(display "Not B is greater.")
(display "Not A is greater."))