Please send questions to
st10@humboldt.edu .
; building on the idea of higher-order functions
; higher-order functions:
; either have one or more parameters that are functions
; AND/OR, returns a function;
; reminder:
; my-map: expects a function and a list,
; and returns the list resulting from applying that
; function to every element in a list
(define (my-map a-funct a-list)
(cond
((null? a-list) '())
(else (cons (a-funct (car a-list))
(my-map a-funct (cdr a-list))))
)
)
(my-map car '((cheese 3.50) (tofu 2.98) (chocolate 4.50)))
; and in higher order functions, it is convenient (or more)
; to have the concept of an anonymous function;
; and McCarthy adapted Church's notation from lambda calculus
; for specifying anonymous functions
(lambda (x)
(+ 3 x)
)
(lambda (length width height)
(* length width height)
)
; the value of each of the these lambda expressions
; is an anonymous function -- of type procedure (!)
; in R5RS Scheme, anyway...
; you apply a named function such as car by simply typing
; its name after an open parenthesis, followed by its
; arguments;
; car is a simple expression of type procedure
; you apply an anonymous function, then, by putting
; a lambda expression after an open parenthesis,
; followed by the arguments for that anonymous function;
((lambda (length width height)
(* length width height)) 3 5 10)
; this is how functions were originally defined in Lisp:
(define box-area
(lambda (length width height)
(* length width height)))
(box-area 3 5 10)
((lambda (a-num) (< a-num 0))
13)
(my-map (lambda (person)
(list "howdy" person))
'("harold" "maude" "alice"))
; and it is quite reasonable, then, to return a function
; by having the function return a lambda expression
; here is a rather silly function that expects 2 arguments
; (of pretty much any type) and produces a function that
; can be used to "combine" those two things...
; 2 numbers? returns a function that adds them
; 2 lists? returns a function that appends them
; 2 non-list non-numbers? returns a function that puts them into a list
; 1 non-list and 1 list? returns a function that cons's them
; 1 list and 1 non-list? appended the list to a list consisting of
; the non-list
(and #t #t)
(or #t #f)
(not #f)
(define (get-combiner thing1 thing2)
(cond
((and (number? thing1) (number? thing2))
(lambda (n1 n2)
(+ n1 n2)))
((and (not (list? thing1)) (not (list? thing2)))
(lambda (item1 item2)
(list item1 item2)))
((and (not (list? thing1)) (list? thing2))
(lambda (item a-list)
(cons item a-list)))
((and (list? thing1) (not (list? thing2)))
(lambda (a-list item)
(append a-list (list item))))
((and (list? thing1) (list? thing2))
(lambda (list1 list2)
(append list1 list2)))
)
)
; expects 2 things, and calls get-combiner to
; get an appropriate function to combine them,
; which it then uses on those things
(define (add-to thing1 thing2)
((get-combiner thing1 thing2) thing1 thing2))
(add-to 1 3)
(add-to 'a 'b)
(add-to '(hi there) 3)
(add-to 3 '(hi there))
(add-to 'hi 3)
(add-to '(1 2) '(3 4))
; a more serious reason for returning a function:
; currying
; (Wikipedia)
; (CS) "currying is the technique of transforming a function taking
; multiple arguments into a function that takes a single argument
; (the first of the arguments to the original function)
; and returns a new function which takes the remainder of the
; arguments and returns the result"
; (named by Christopher Strachey after logician Haskell Curry
; (and that's the namesake for the Haskell functions=al language...)
; although it was invented by Schonfinkel and Frege...!)
(define (plus x y)
(+ x y)
)
; the curried version of plus would take a single argument x and
; return a new function which takes a single argument y and
; returns x + y
(define (curried-plus x)
(lambda (y)
(+ x y))
)
(curried-plus 1) ; produces a function that adds 1 to its argument
((curried-plus 1) 28)
(curried-plus 100) ; produces a function that adds 100 to its argument
((curried-plus 100) 27)
; in theoretical CS, currying gives you a way to study functions
; with multiple arguments in very simple theoretical models
; (like the lambda calculus) where functions can only take
; a single argument...
; in a practical sense, sometimes the resulting functions are
; useful (++, anyone?)
; Haskell, ML provide syntactic sugar for currying --
; but any language w/ support for higher-order functions
; should be able to used to write curried functions...
; let/let*/letrec are ways to locally give a name a value
; in Scheme/LISP for convenience -- more on this later;
; interactive input:
; read function: expects no arguments
; when evaluated, it stops until the user types something
; ended with a return/enter
; and its value is what the user types
(read)
(< (read) (read))
; yes, there's file i/o too...