
Functional Parameters in Tom's Lisp
Many languages allow parameters to have values which are functions.
In C, this feature is useful, but only seen occasionally.
In Lisp, this feature is used much more often, frequently by
sending anonymous functions. For instance, one of the
standard functions in Tom's Lisp is map. Map takes
a one-argument function and a list, and returns a new list of
the result of applying the function to each member of the list.
For instance:
lsp>(define (addone x) (+ x 1))
addone
lsp>(map addone '(5 9 8 12))
(6 10 9 13)
Here, we defined a small function which just takes its argument and
increments it. When we map this to the list (5 9 8 12), we simply
add one to each element to produce (6 10 9 13).
Of course, we don't need to use a named function:
lsp>(map (lambda (x) (+ x 1)) '(5 9 8 12))
(6 10 9 13)
Here, we've done the same thing by sending an anonymous function to
add one.
The map function itself is simple:
; Map a unary function and return a list of the results.
(define (map f lis)
(if (null? lis) lis
(cons (f (car lis)) (map f (cdr lis)))
)
)
The parameters are there for the function and the list. If the list
is empty, the result is also the empty list. Otherwise, apply
f to the first member of the list, recur on the balance of the
list, and glue the result back together.
The second standard Tom's Lisp function which takes
a functional parameter is reduce. It takes a two-argument
function, a list, and and a starting value. It applies the function
the starting
value and the first member of the list, then uses this value to combine
with the second list value, and so forth, returning the result after the
last list member. Instead of all that complexity, think: Add it up:
lsp>(reduce + '(4 9 8 1 2) 0)
24
This adds 0 and 4, then 4 and 9, then 13 and 8, then 21 and 1, then
22 and 2, and returns the 24. Want the sum of the squares instead?
lsp>(reduce + (map (lambda (x) (* x x)) '(4 5 12 17 4 8)) 0)
554
Or would you like this this way?
(reduce (lambda (sum x) (+ sum (* x x))) '(4 5 12 17 4 8) 0)
554
This also gives us a peculiar way to write the list length function:
(define (demented-length lis)
(reduce + (map (lambda (x) 1) lis) 0)
)
lsp>(demented-length '(4 12 39 8))
4
lsp>(demented-length '(how is this doing today))
5
In demented-length, we use an anonymous function which always returns
one. When we map it to any list, we get a list of ones with the same length.
Using reduce and addition, we compute the sum of the ones which is
the list length.
Thirdly, the select function is used to choose from a list
only those members desired. Select accepts
a function and a list. The function is a predicate of one argument.
It is run on each member of the list and returns true or false. The
select function returns those members for which the function is
true.
lsp>(select (lambda (x) (<= x 10)) '(4 9 20 13 7 18 1 0 41 8))
(4 9 7 1 0 8)
lsp>(select (lambda (x) (not (pair? x)))
--->'(4 6 tom (x y z) 2 17 ((x)) (1 2) 9))
(4 6 tom 2 17 9)
lsp>(select int? '(1 2 3 cant catch me (or me) 99))
(1 2 3 99)
lsp>(select (lambda (x) (not (= x 4))) '(3 9 18 17))
(3 9 18 17)
lsp>(select (lambda (x)(= x 4)) '(3 9 18 17))
nil