A Note on Declarative Programming Paradigms and the Future of Definitional Programming
Total Page:16
File Type:pdf, Size:1020Kb
A Note on Declarative Programming Paradigms and the Future of Definitional Programming Olof Torgersson∗ Department of Computing Science Chalmers University of Technology and G¨oteborg University S-412 96 G¨oteborg, Sweden [email protected] Abstract where the need for a higher level of abstraction and a clear semantic model of programs is obvious. We discuss some approaches to declarative programming in- The basic property of a declarative programming lan- cluding functional programming, various logic programming guage is that a program is a theory in some suitable logic. languages and extensions, and definitional programming. In This property immediately gives a precise meaning to pro- particular we discuss the programmers need and possibilities grams written in the language. From a programmers point to influence the control part of programs. We also discuss of the the basic property is that programming is lifted to a some problems of the definitional programming language higher level of abstraction. At this higher level of abstrac- GCLA and try to find directions for future research into tion the programmer can concentrate on stating what is to definitional programming. be computed, not necessarily how it is to be computed. In Kowalski’s terms where algorithm = logic + control, the 1 Introduction programmer gives the logic but not necessarily the control. According to [30] declarative programming can be un- Even though declarative programming languages have been derstood in in aweak and a strong sense. Declarative pro- around for some thirty years by now they have still not gramming in the strong sense then means that the program- gained any widespread use for real-world applications. At mer only has to supply the logic of an algorithm and that all the same time object-oriented programming has conquered control information is supplied automatically by the system. the world and is the methodology used for most programs Declarative programming in the weak sense means that the developed today. This is a fact even though the used object- programmer apart from the logic of a program also must oriented languages like C++ lacks most features considered give control information to yield an efficient program. important in declarative programming like a clear and sim- ple semantics, automatic memory management, and so on. 2.1 Functional Programming It should be obvious that the object-oriented approach con- tains something that is intuitevely appealing to humans. Ac- In functional programming languages programs are built cordingly many attempts have been made to include object- from function definitions. To give meaning to programs oriented features into declarative programming and several they are typically mapped on some version of the λ-calculus languages like Prolog and Haskell have object-oriented ex- which is then given a denotational semantics. There are tensions both impure (strict) functional languages like Standard ML In this note we discuss some existing declarative pro- [32] allowing things like assignment and pure (lazy) func- gramming paradigms including definitional programming. tional languages like Haskell [24]. In particular we will focus on control and also try to iden- Modern functional languages like Haskell come rather tify some characteristics that we feel it is necessary to in- close to achieving declarative programming in the strong corporate in the next generation definitional programming sense since programmers rarely need to be aware of control. language to gain success. On the other hand the execution order of lazy evaluation is not very easy to understand and the real computational content of a program is hidden under layers and layers of 2 Declarative Programming Languages syntactic sugar and program transformations. As a conse- quence the programmer loses control of what is really going Most declarative programming languages stem from work in on and may need special tools like heap-profilers to find out artificial intelligence and automated theorem proving, areas why a program consumes memory in an unexpected way. ∗ This work was carried out as part of the work in ESPRIT working To fix the behavior of programs the programmer may be group GENTZEN and was funded by The Swedish Board for Indus- forced to rewrite the declarative description of the prob- trial and Technical Development (NUTEK). lem in some way better suited to the particular underlying implementation. Thus, an important feature of declarative programming may be lost – the programmer does not only have to be concerned with how a program is executed but has to understand a model that is difficult to understand and very different from the intuitive understanding of the program. However, functional programming languages provide many | ?- findall(Xs,subset([1,2,3],Xs),Xss). elegant and powerful features like higher order functions, strong type systems, list comprehensions, and monads [43]. Xss = [[1,2,3],[1,2],[1,3],[1],[2,3],[2],[3],[]] Several of these notions are being adopted in other declara- tive programming languages (see below). While the built-in search gives powerful problem solv- Functional languages also support reusing code and come ing capacities to the language it also makes the evaluation with a large number of predefined functions. While heavy principle more complicated. Accordingly, Prolog and most use of such general functions give shorter programs it is not other logic programming languages only provide declara- obvious that it makes programs easier to understand. An tive programming in the weak sense where the programmer example of a general list reducing function is foldr which also need to provide some control information to get an ef- can be used to define almost any function taking a list and ficient program from the declarative problem description. reducing it somehow: The method used by many Prolog programmers is rather ad hoc: First the problem is expressed in a nice declarative fun foldr _ u nil = u fashion as a number of predicate definitions. Then the pro- | foldr f u (x::xs) = f x (foldr f u xs) gram is tested and found slow. To remedy the problem the original program is rewritten by adding control information Functional programming methodology makes heavy use of (cuts) as annotations in the original code and doing some foldr and similar functions to define other functions recurs- other changes like changing the order of arguments to pred- ing over lists. For instance the function len can be defined icates. The resulting program is likely to be quite different from the original one – and less declarative. As an example, val len = foldr (add o K 1) 0 assume that we wish to define a predicate lookup that finds where add computes the sum of two integers and K is the K a certain element in a list of pairs of keys and values. If the combinator. We leave up to the reader to understand how element is missing the result should be the atom notfound. this definition works. A first definition could be: Heavy use of general higher-order functions, function lookup(Key,[],notfound). composition, list comprehensions and so on, makes it possi- lookup(Key,[(Key,Value)|_],Value). ble to write very short programs but it also turns functional lookup(Key,[_|Xs],Value) :- lookup(Key,Xs,Value). programming into an activity for experts only since it be- comes impossible for non-experts to understand the result- However if we compute lookup(1,[(1,a),(1,a)],V) we will ing programs. get the answer V = a twice and the answer V = notfound once. Of course in this case we have a logical error but the 2.2 Logic Programming program can be rewritten using the same logic giving only one answer: For practical applications there exists one logic program- ming in use: Prolog. Prolog is used for a wide variety of lookup(Key,[],notfound). applications in artificial intelligence, knowledge based sys- lookup(Key,[(Key,Value)|_],Value) :- !. tems, and natural language processing. A (pure) Prolog lookup(Key,[_|Xs],Value) :- lookup(Key,Xs,Value). program is understood as a set of horn clauses, a subset The cut (!) means that the third clause is never tried if of first order predicate logic, which can be given a model- the second can be applied. Note how this destroys the logic theoretic semantics, see [27]. Programs are evaluated by of the program (even if it gives the desired answers). A proving queries with respect to the given program. more efficient version can be defined if we swap the order of From a programming point of view Prolog provides two the two first arguments since it will allow the compiler to features not present in functional languages, built-in search generate better code. Prolog also includes loads of impure and the ability to compute with partial information. This features like arithmetic, meta predicates, operational I/O, is in contrast to functional languages where computations and so on. All in all there exist few real Prolog programs always are directed, require all arguments to be known and which are truly declarative. give exactly one answer. A simple example of how predicates It is possible to incorporate notions like monads and list can be used to compute in several modes and with partial comprehensions into logic programming. For instance [8] information is the following appending two lists: shows how it can be done in the higher-order language λ- append([],Ys,Ys). Prolog. append([X|Xs],Ys,[X|Zs]) :- append(Xs,Ys,Zs). There are also languages trying to overcome the deficien- cies of Prolog by providing cleaner mechanisms for control Not only can append be used to put two lists together but and meta-programming. An example is the language G¨odel also to take a list apart or to append some as yet unknown [23] which is a typed language based on a many-sorted logic.