The performance overhead is no worse than calling a virtual method in any contemporary OO language.
It makes sense to pass procedures to other procedures when it makes your code smaller. Less code has fewer bugs and is easier to maintain. Here's an example. These are two functions that respectively sum a list of numbers and multiple a list of numbers.
(define sum
(lambda (ls)
(if (null? ls)
0
(+ (car ls) (sum (cdr ls))))))
(define product
(lambda (ls)
(if (null? ls)
1
(* (car ls) (product (cdr ls))))))
They're identical except the operators +
and -
and the corresponding identity value (0
and 1
). We've unfortunately duplicated a lot of code.
We can reduce complexity by abstracting the operator and the identity. The rewritten code looks like this.
(define fold
(lambda (proc id)
(lambda (ls)
(if (null? ls)
id
(proc (car ls) (fold (cdr ls) proc id))))))
(define sum (fold + 0))
(define product (fold * 1))
It's easier now to see the essential difference between sum
and product
. Also, improvements to the core code only have to be made in one place. Procedural abstraction is a fabulous tool, and it depends on being able to pass procedures to other procedures.