------------------------------------------------------------------------------
MC logo
Functional Parameters in Tom's Lisp
[^] Tom's Lisp
------------------------------------------------------------------------------
[Basic Input Format] [Lists, Pairs and Related Operations] [Conditional Evaluation] [Basic Function Definition] [Definitions and Scope] [Functions Which Take Functions] [String Functions] [Exception Handling] [Quoting And Evaluation] [Variable-Length Parameter Lists] [Macro Definitions] [Printing] [The Tomslsp command and its switches] [Index of Standard Functions]

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