Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP
Path: utzoo!mnetor!seismo!vrdxhq!verdix!ogcvax!pase
From: pase@ogcvax.UUCP (Douglas M. Pase)
Newsgroups: comp.lang.misc
Subject: Re: H.O.Functions + Polymorphism
Message-ID: <1345@ogcvax.UUCP>
Date: Wed, 8-Jul-87 00:43:44 EDT
Article-I.D.: ogcvax.1345
Posted: Wed Jul  8 00:43:44 1987
Date-Received: Sat, 11-Jul-87 03:07:33 EDT
References: <...> <2637@crcge1.UUCP> 
Reply-To: pase@ogcvax.UUCP (Douglas M. Pase)
Distribution: world
Organization: Oregon Graduate Center, Beaverton, OR
Lines: 92

In article  gudeman@arizona.edu (David Gudeman) writes:
>
>Any language with functions can have higher order functions, and any
>language with the concept of `arguments' can have lazy evaluation of
>them.  So how can these features be called advantages of functional
>programming?

Well, imperative languages do not support these features, and higher order
functions, at least, are a central issue to functional programming.  Because
imperative languages are modeled somewhat after the machines they run on,
having storage locations, addresses and state, such concepts are really
incompatible with them.  Higher order functions are not really blocks of
code which have a starting address.  They are more complex than that.  I
will try to illustrate.

'C' is one of the more flexible imperative languages.  It allows one to
pass the address of functions to other functions.  In some sense, this is
a higher order function.  However, it does not allow the full range of
flexibility that higher order functions are allowed.  For example, one
is not able to directly bind arguments to a function and thereby create
a new function.  Take for example a function that I'll call 'plus'.  (I
leave it to the interested reader to figure out just what this function
does.)  One common feature of languages which directly support higher order
functions is that 'plus' can be partially bound to form a new function --

	let p1 = plus 1;

would define a new function, 'p1', which uses the function 'plus' and gives
it an argument.  If we assume the type of 'plus' is

	plus : int -> (int -> int)

then the type of 'p1' would be

	p1 : int -> int

In other words, "p1 5" is an integer expression, and "p1" is an integer
function.  "plus" could be viewed as a function which takes two integer
arguments and returns an integer result, or as a function which accepts
an integer argument and returns an integer function.  Both views are
compatible.

This view of functions is thoroughly incompatible with that of any imperative
language.

Now, combine this idea with polymorphic types.  A polymorphic type is a
data type which may take a type value of many different types -- that is,
it may be a list sometimes, or an integer, a pair, or list of pairs, etc.
It may not be more than one type at a time.  The easiest way to explain this
is with an example.

	letrec listcount = \ list .	/* the '\' says 'list' is an arg */
		if list = [] then	/* the list is empty */
			0		/* the count is zero */
		else			/* count the remains & add 1 */
			1 + listcount (tail list)
	;

This is a simple function which counts the elements of a list.  Its type is

	listcount : list(*a) -> int

Notice that the list argument is polymorphic -- that is, it can take on any
type.  But lists cannot have elements that are of different types.  A list
may have integer elements, but if it does it cannot have elements of other
types.  Thus I may say

	listcount [1;2;3]
or
	listcount ['a';'b';'c']

even though the arguments have different types (list of integers vs. list
of characters).  Notice that

	listcount [1;'b';(3,4)]

is not legal because the elements of the list all have different types.
This is all to say that polymorphic types can still be strongly typed
(that is, no type errors will go undetected).  I leave it to your imagination
to see how these features might help in the software reusability problem.

I do not yet see the advantages to lazy evaluation except in a few cases
which are academically interesting but of little practical use (all of which
involve an exact representation of an infinite sequence, such as the digits of
an irrational number).  However, lazy evaluation is not supportable in
imperative languages as it is an 'evaluate on demand' strategy for function
parameter evaluation.  All imperative languages evaluate the arguments to
functions before the function is invoked.  I have not studied this particular
feature (lazy evaluation) in any great depth so my understanding may well be
partial.
--
Doug Pase   --   ...ucbvax!tektronix!ogcvax!pase  or  pase@Oregon#!lualualray