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