Translating Functional Programs to GCLA Olof Torgersson Department of Computing Science Chalmers University of Technology and Goteborg University S-412 96 Goteborg, Sweden
[email protected]
Abstract
We investigate the relationship between functional and de nitional programming by translating a subset of the lazy functional language LML to the de nitional language GCLA. The translation presented uses ordinary techniques from compilers for lazy functional languages to reduce functional programs to a set of supercombinators. These supercombinators can then easily be cast into GCLA de nitions. We also describe the rule de nitions needed to evaluate programs. Some examples are given, including a description of how translated programs can be used in relational Prolog-style programs, thus giving yet another way of combining functional and logic programming.
1 Introduction Dierent techniques for transforming functional programs into various logic programming languages have been around for long and goes back at least to the earlier days of Prolog-programming [19]. Some of these, like the transformation described in [14], are used to augment a logic programming language with syntactic sugar for functions, while others, for instance [15], tries to give a model for functional evaluation in logic programming. In this paper we present a translation from a subset of a lazy functional language into the de nitional programming language GCLA [1, 13]. The presented translation has its origins in a project where we planned to apply KBS-technology to build a programming environment for a lazy functional language. The translation into GCLA was then intended to be the representation of functional programs This work was carried out as part of the work in the ESPRIT working group GENTZEN and was funded by The Swedish National Board for Industrial and Technical Development (NUTEK).
1
De nitional Programming in GCLA: Techniques, Functions, and Predicates
in a system to do debugging etc. The programming environment was never realized but we would like to regard the translation presented as an empirical study giving some kind of intuitive feeling for the similarities and dierences between functional and de nitional programming. Also readers familiar with the attempts to implement functions by desugaring them into logic will be able to nd interesting relations to our work. The basic idea in our translation is to use ordinary techniques from compilers for functional languages to transform the functional programs into a simple form, a number of supercombinator de nitions [16]. These supercombinator de nitions can be easily mapped into the partial inductive de nitions [9] of GCLA. We then make use of the two-layered nature of GCLA programs, where the declarative content and the procedural information of an application are divided into two separate de nitions, to cast the supercombinators into one de nition and give a rule de nition describing the procedural knowledge needed to evaluate this de nition correctly. The presentation of the resulting de nitions, and the procedural part used to evaluate these is carried out in some detail to illustrate GCLA programming and contribute to de nitional programming methodology. The rest of this paper is organized as follows. Sections 2 and 3 describe a small functional language and a mapping from this language into GCLA de nitions. In Section 4 we give the inference-rules and search-strategies needed to give a procedural interpretation of the GCLA de nitions produced. In Section 5 we present some examples, including a discussion of how translated functional programs may be integrated with de nitional logic programs. Finally in Section 6 we discuss some alternative translations and connections to attempts at doing lazy evaluation in logic programming.
2 A Tiny Functional Language Since our original aim was to apply KBS technology to build an environment for program development, we choose to work with a subset of an existing programming language. The language chosen is a very small subset of LML [3, 5] that we call TML (for tiny ML). TML is a subset of LML in the sense that any correct TML program also is a correct LML program. LML is today falling in oblivion in favour of the standardized language Haskell, but was still very much alive when we started our work. For the small subset we are considering this is not very important however since the only dierence, if we used a subset of Haskell instead, would be some minor changes of syntax in the functional source programs. The major limitation made in TML is that there are no type declarations in the language, that is, it is not possible to introduce new types. The only possible types of objects in TML are those already present in the system, namely integers, booleans, lists and tuples. Although this is a serious limitation, we do 2
Translating Functional Programs to GCLA not believe that the translation into GCLA presented in this paper would be seriously aected if we introduced the possibility to declare new types. The new type constructors declared could simply be treated in the same manner as the constructors of the prede ned types. We do not present any formal syntax of TML but instead illustrate with some examples. A program de ning the functions append, foldr, fromto and flat is: let rec || and || and
append nil ys = ys append (x.xs) ys = x.append xs ys foldr f u nil = u foldr f u (x.xs) = f x (foldr f u xs) fromto n m = if n = m+1 then nil else n.fromto (n+1) m and flat xss = foldr append nil xss in flat [fromto 1 5;fromto 2 6 ;fromto 3 7]
As can be seen from this example a program consists of a number function de nitions followed by an expression to evaluate which gives the value of the program. The dierent equations de ning functions are separated by `||' and lists are built using the constructors `.' and nil. The most peculiar syntactical feature is that elements in lists are separated by `;'. The rst example shows that TML includes typical functional programming language properties like pattern matching and higher-order functions. Our next example, implementing the sieve of Eratosthenes, also makes use of lambda abstractions and lazy evaluation. The lambda abstraction x:E is written \x.E: let rec filter p nil = nil || filter p (x.xs) = if (p x) then x.(filter p xs) else filter p xs and from n = n.from (n+1) and take 0 _ = nil || take n (x.xs) = x.take (n-1) xs and sieve (p.ps) = p.sieve (filter (\n.n%p ~=0) ps) in take 20 (sieve (from 2))
3 Translating TML programs into GCLA First order function de nitions can be naturally de ned and executed in GCLA, see [1, 18] for details. As a very simple example consider the identity function id de ned for a data type consisting of the single element zero: zero [], 'False' => [Y|take(N - 1,Ys)]]]. main even(N - 1)]. even(N) 'True', _ => odd(N - 1)]. main 1 + len(Ys)].
Now, the case expressions can be removed and represented with arrows len(Xs) Ys) -> (equal(Ys,[]) -> 0),
18
Translating Functional Programs to GCLA (equal(Ys,[_|Zs]) -> 1+len(Zs)). equal(X,X).
a de nition that can be executed using only the rules of FL [18], which so to speak gives a basis for functional evaluation in GCLA. Alternatively each case expression can form a basis for the de nition of an auxiliary function performing matching: len(Xs) Zs. lencase(_,[]) '). :- op(800,yfx,$). :- multifile(constructor/2). :- include_rules(lmlmath). constructor(=,2). constructor(case,1). constructor(of,2). constructor('=>',2). constructor($,2). constructor(cls,2). constructor(let,2). %%% Definitional Rules d_left(PT) ([Dp] \- C)) -> ([T] \- C). d_ax ([T] \- C). %%% Cases and Equality case_left(PT1,PT2) ([E] \- C1)), memberchk( =>(C1,V),L), (PT2 -> ([V] \- C)) -> ([case(of(E,L))] \- C). eq_left(PT1,PT2,PT3) ([X] \- X1)), (PT2 -> ([Y] \- Y1)), (PT3 -> ([eq(X1,Y1)] \- C)) -> ([X=Y] \- C). %%% Higher Order Functions fn_ax ([T] \- C). apply(PT) ([fn(N,Ys)] \- C)) -> ([(fn(N,Xs)$ X)]\- C). normalorder(PT1,PT2) ([M] \- M1)), (PT2 -> ([(M1$ N)] \- C)) -> ([(M$N)] \- C). %%% Closures for Lazy Evaluation lazy(1,Q,PT) ([X] \- C1)), new_closures(C1,C), unify(Y,C)
24
Translating Functional Programs to GCLA -> ([Q] \- C). lazy(2,Q,PT) ([Q] \- C). let(PT) ([E] \- C)) -> ([let(Defs,E)] \- C). % Strategies tml