Academia.eduAcademia.edu

Learning programming in Prolog using schemata

1998, ACM SIGPLAN Notices

In the paper, we describe our approach and experience with teaching fundamentals of logic programming by program schemata construction and explanation. Program schemata construction is helped by presentation of a few examples. After a particular program schema has been introduced, students are required to instantiate the schema both as a writing exercise and afterwards as a programming exercise. We report on our experiments aimed at verifying our hypotheses about suitability of this approach to learning programming by evaluating the effectiveness of the learning process.

Learning Programming in Prolog Using Schemata* Mfiria Bielikov~, Pavol N~vrat Slovak University of Technology, Dept. of Computer Science and Engineering, Ilkovi6ova 3, 812 19 Bratislava, Slovakia E-mail: {bielik, navrat}@elfstuba.sk WWVK"http://www.elf.stuba.sk/~{bielik,navrat] Abstract. In the paper, we describe our approach and experience with teaching fundamentals of logic programming by program schemata construction and explanation. Program schemata construction is helped by presentation of a few examples. After a particular program schema has been introduced, students are required to instantiate the schema both as a writing exercise and afterwards as a programming exercise. We report on our experiments aimed at verifying our hypotheses about suitability of this approach to learning programming by evaluating the effectiveness of the learning process. Key words: logic programming, Prolog, program schemata Introduction Nowadays, learning programming is one of the basic educational activities of any student of computer or software related curriculum. Besides the "classical" procedural programming paradigm, and the "inevitable" object-oriented paradigm, learning programming functionally and programming logically is a standard component of the curriculum offered by Slovak University of Technology in Bratislava. In the paper, we describe our approach and experience with teaching fundamentals of logic programming by program schemata construction and explanation. Our approach can perhaps best be expressed as designing, explaining, and applying program schemata. We rely on explaining a relatively large number of examples of predicates. As it is frequently the case, Prolog is our language of choice despite its known shortcomings when considered as a pure logic programming language. Program schemata (generalizations), programming techniques or plans (abstractions) all represent various kinds of programming (meta-) knowledge. We find it important to make the knowledge explicit for the learner [9, 3, 10]. A schema-based approach facilitates learning of general programming techniques by requiring the stu- dent to instantiate templates which are generalizations of a program to solve the assignment. This instructional technique has proven useful when recursion (a very difficult concept for most novice programmers [7]) is taught. It can be argued that one of the causes of difficulties is the lack of a structured programming construct for recursion in programming languages like Prolog and Lisp [1]. A schema-based approach enables to alleviate some of these difficulties by providing novice programmer with a set of standard structures (or program schemata) with which one is able build complex and interesting recursive Prolog programs [6]. In the rest of the paper, we describe the method of teaching logic programming together with some of the schemata that we employ in teaching. We report on our experiments aimed at verifying our hypotheses about suitability of this approach with respect to learning programming by evaluating the effectiveness of the learning process. Method of t e a c h i n g To be able to form relatively large and practically interesting programs in Prolog requires to master only "a few" syntactical constructs. However, it would be most naive to expect that based on that fact, programming in Prolog can be learnt very swiftly and simply. More likely, the opposite is true [2]. To be able to form both elegant and efficient logic (Prolog) programs requires as a rule a considerable programming experience. Additional difficulty is inter-paradigmal transition, as manifested by the problems that experience many our students who had mastered quite extensively the procedural paradigm. Some of them seem to be constrained to the extent that their understanding of the alternative paradigm effectively is blocked (of. similar experience reported in [8]). We teach logic programming as a part of the subject Functional and Logic Programming. The *The work reportedhere was partiallysupportedby SlovakScienceGrant AgencygrantNo. G1/4289/97. ACM SIGPLAN Notices 41 V. 33(2) February 1998 subject is covered in one semester (13 weeks). The relative modesty of its extent forces to concentrate on the foundations of logic programming (which constitutes only a part of the subject's contents; besides it, functional programming is treated, too). We aim to help learners understand the essence of this programming paradigm. We also aim to achieve this by a learning process that involves practical problem solving. Again, the subject's extent constraints this aspect as only relatively short programs can be explained or devised. "Larger" programs with several dozens or hundreds of predicates are written by students when completing their assignments for subjects Artificial Intelligence or Knowledge Based Systems. Respecting the above considerations, our approach is an attempt to convey the programming experience to the students in a most useful i.e., comprehensive, effective and complete way. We realise that without compressing in time the experience gathering phase, the student would not be able even to approach the desired level of mastery of Prolog programming in such a short period. What is urgently needed is a means to express the programming knowledge in a possibly standardized way, so that the learners can acquire the accumulated experience via a shortcut route. We propose program schemata as a way of expressing standard programming solutions. As a consequence, we hope to achieve more balance between the inventive dimension of programming (i.e., programs are original programmer's inventions), and the engineering dimension of programming (i.e., programs are original technical solutions developed from standardized skeletal solutions by applying standardized procedures and respecting technical standards). Our basic assumption in teaching logic programming (but similarly also functional programming) is that many programs (e.g., those which are concerned with list processing) have a similar structure so that they can be considered instances of some program schema. Our approach fosters acquiring basic programming techniques. The learner forms instances of schema (replaces or refines generic parts of a schema) and in such a fashion solves the assigned problems. Schemata for processing of lists Our students can be considered novices in progrannning, especially with respect to the logic paradigm. Therefore we restrict ourselves to prob- lems in which no indirect recnrsion is involved or no operations with side effects are involved (such as input/output). Only gradually, when proceeding to solving more complex problems, other schemata are presented (e.g., meta-predicates, control predicates such as cut, input/output, etc.). Schemata are based on a typical structure of predicates for certain classes of problems. One of the important issues in teaching them is the order in which the learners become acquainted with the different schemata. In our approach, we distinguish two basic classes and proceed accordingly in two steps: 1. list processing at its top level only, 2, list processing at all levels. In both classes, we define pairs of similar problems e.g., substituting a symbol in a list by another one at the top level of the list, and similarly, substituting a symbol in a list by another one at all levels of the list. Our experience for several years has been that the students can cope better with the kind of problems from the former class. In other words, to program processing of lists at all levels seems to be more difficult for our students. That is why we start teaching the former class and proceed to processing at all levels only later. In Fig. 1, a hierarchy of program schemata for processing of lists is outlined. The schemata identified in Fig. 1 can be found in Appendix. In the case of processing of lists at all levels, the classes of problems are the same. We use the following general schema of processing of lists at all levels: DList([HIT] &V1) :DList(H &V2), DList(H &V3). DList(E &V1) :Process(E &V2). How the program schema is represented? Our utmost objective has been simplicity. We deliberately avoid introducing any unnecessary complexity, such as a new, different formalism when new concepts can be satisfactorily represented using a known language, perhaps with only a minor enhancement. We use two kinds of variables: programming language variables (Prolog variables) and schema variables (variable predicate symbols). Variables begin with a capital letter. Schemata that express classes of predicates with various numbers of clauses or various numbers of conditions in clauses are represented using an additional optional symbol. This symbol allows to mark place for a Schema ) I (Reduce) (Map ) (Filter) (Predicate) I !e Count ' ( Remove-if ) (Remove-if-no0 I ,omeno, (Count-if) (Count-if-not) Fig. 1. Hierarchy of program schemata for processing of lists. clause or a condition that may but need not occur in a definition of a particular predicate of the class expressed by the schema. The optionality is represented by brackets. Optional arguments in terms are represented by the symbol &. For example in the above schema the oeeurenees of the expression &Vl can be replaced by a sequence of any number of arguments (including none). The condition in the third clause is optional. In all the schemata we use a generalised optional argument (in form of &Vi). It expresses an option that the schema instance (i.e., the particular predicate) can involve additional arguments. Our position is that such additional arguments are not crucial from the point of view of the programming knowledge that is expressed by the schema. To add them is more or less a matter of routine. Therefore, we shall not mention them from now on. Experiments To find out more about the effectivenes of our approach, we conducted some experiments with the spring of 1997 class. It is useful to repeat here the fact that before coming to learn programming in Prolog, the students spend the first part of the subject learning functional programming (Lisp). The reason why we use this particular order has been more or less pragmatic. However, we note that to discuss and ask about the order in which a learner studies different programming paradigms is a legitimate question in its own right. Experimentation method There were two groups of students. Only to one of them a catalogue of program schemata was made available during the test. The eatalague included several schemata (e.g., five for one particular prob!em)t. S0m.e problems could be solved using some of the schemata directly. There were other problems that could be solved by combining some schemata from the catalogue, or by specialising them. In order to eliminate possible influence of other factors, schemata are named so that the names do not reveal the essence of the processing. For example, the schema for counting those elements of a list at the top level which share the given property was presented to students in the following form: Schema-l([], 0). Schema-l([H l T], C) :Predicate(H), Schema-l (T, CL), C i s C L + 1. Schema-l([HI T], C) :[Not-Predicate(H),] Schema-l(T, C). Across both groups, there were students with two different preconditions. Attending lectures is not obligatory for the students and consequently, there is usually a part of the class not present. Some students were present at the previous week's lecture when the schemata were introduced and explained to a considerable detail. The complement of the class can be assumed to be practically ignorant (the version of our textbook available at that time did not include program schemata). Results and evaluation There were 101 students who took part in the experiments, all of them level 3 students of our baccalaureate Informatics course in the software engineering track. There were 53 students among them who have already heard about schemata, but the remaining haven't. During the test, 47 students had available the catalogue of schemata, but the remaining had not. Distribution of the whole set of students into the four categories is shown in Tab. 1. 43 Schemata available? no .___.~yes r Explanation received? yes [ 22 31 no [ 25 23 Tab. 1. Distribution of students into groups. Perhaps the most important question to answer when trying to evaluate the approach to learning logic programming based on program schemata is concerned with a positive identification of their influence on students' learning process. In our formulation, does the use of schemata in learning logic programming influence results o f novice learners? Can it speed up the process of learning the paradigm? We can formulate our first hypothesis: The results after using schemata are better. To judge about the results, we tested the whole elass. All the students (in one place at one time) were supposed to solve very simple problems by devising appropriate predicates. In Tab. 2 we display the overall results of tests of students from all the four subgroups (cf. Tab. 1) either based on their marks out of 4, (i.e., marks from the range <0,4>), or expressed as a relative portion (per cent) of correct solutions within each subgroup. Schemata available? yes no Explanation yes 3.66 3.45 no 3.15 2.62 Explanation 77% 74°/. received? 56% 28% received? b Tab. 2. Overall results of tests. The results in Tab. 2 allow some conclusions. Best results were achieved by the students who had prior information on schemata and at the same time they had the catalogue of schemata at hand during the test. 77% out of them produced correct solutions. Second best results (74%) were achieved by those students who had the catalogue o f schemata at hand during the test but did not hear their pres- entation and explanation. Comparing to them, students who heard the presentation and explanation but did not have the catalogue of schemata at hand during the test performed worse (56%). By far the worst results were achieved by the subgroup without prior information and without schemata. The results of the first two subgroups show clearly that schemata influence positively the students' programming performance. It is perhaps surprising that their results are so close. However, here it is worth noting that the whole class was at that point already having some experience with program schemata, because in the first part o f the semester, schemata for functional programming were taught in a similar way. This is indirectly endorsed by similar experiments of ours related to using schemata in teaching functional programming. The second and third subgroups scored almost precisely the same there. Here (after some experience with program schemata), for the students it was more valuable to receive the catalogue of Prolog related schemata and to have it during the test. Another question which is frequently discussed with respect to learning programming concerns the role o f computer and importance of its direct usage when solving a programming problem. A quite frequent pattern o f a student's problem solving procedure includes an initial sketch of a design of the solution on a paper and then an interaction with a computer during which implementation of the solution is attempted to be completed. We shall refrain in this paper from commenting on such a pattern with respect to its appropriateness etc. We wanted to find out whether the peculiar variety of the trial and error method is applied because of greater comfort or because o f inability to devise a correct solution by using paper and pen only. We have found out that 39% o f all students had the correct solution already sketched on a paper. Next 30% of all students not only did not have a correct solution designed on a paper, but could not arrive to one even during the interaction with a computer. The remaining 31% was able to make some minor changes like amending or completing tests in clauses' bodies. The likely conclusion is that in most cases, direct usage of a computer when solving a programming problem does not have a clearly positive effect. It is partially in conflict with our experience from the previous years when logic programming was taught without program schemata. 44 . ~. Another hypothesis which we at-tempted to get confirmed or refuted was the one related to the question if problems of processing lists at all levels are harder to solve for learners than processing lists at the top level only. Our hypothesis is: Processing a list at all levels is more difficult to program for learners. We based our hypothesis on our several years' experience. Now, in the experiments reported here we specifically evaluated the success rate of students for the two classes of problems. In Tab. 3, the results show that indeed the students perform better when programming processing of lists at the top level only. However, the difference is quite small, perhaps thanks also to the previous experience with functional programming. On the other hand, a similar evaluation with respect to functional programming did not confirm the hypothesis. The students treated the lists to be processed at all levels as binary trees which they were able to program equally "easily" as processing lists at the top level only. We claim that this result also supports positive influence of the use of program schemata. dpmarks out of 4 | I processing at the top level only I 3.24 [ processing lists at all levels I 3.18 I Tab. 3: Average success rate of solving processing of lists. Students 'feedback At the end o f semester, we initiated an enquette in order to solicit their feedback regarding the subject Functional and logic programming and specifically our approach based on program schemata. The table below summarizes the distribution of responses to one o f the questions in the questionnaire. It shows that a majority of students uses the program schemata (first three answers, i.e. 78% of all students). "Which is the way you use program schemata in designing simple functions/predicates for processing lists?" I write it on a paper I recollect it in my mind I think my using of schemata is automated and I do not consciously realise it I know what schemata are but I do not use them I do not know what schemata are 17% 27% 34% 21% 1% Conclusions In the paper we present the program schemata which we use in teaching logic (Prolog) programming and the way how to represent them. Similar approach to logic programming has been described by Gegg-Harrison [5, 6]. He described 14 basic schemata for recursive predicates together with a way of organizing the dialog in a tutoring system. In [13] is presented an extension of GeggHarrison's proposal for schema language. Our approach differs in choosing a different set of schemata and in focusing to various identified kinds of problems related to list processing. After all, list processing can be viewed as a very general class o f computations. Moreover, our approach reflects consequently our ultimate goal - to support the learning process. In [11], too, there is defined a number of constructs suitable for building Prolog programs (program skeletons and techniques which extend skeletons and express steps in program construction). Separation of control flow and technique is the key idea of this approach. Student selects a skeleton and then enhances it, using standard techniques, to solve his or her particular problem. We feel that to understand skeletons can be rather difficult for novices without having some preceeding experience in building and fully understanding some programs. Our approach is focused on leaming programming with schemata. The method is around building catalogue of program schemata (ultimately to be stored in learners' mind). This is the reason why the simplicity of program schemata representation is crucial. We realise that formal methods for representing program schemata, such as those presented in [4, 12, 13], are important and inevitable when exploring properties o f a created solution, its correctness, etc. Formalising is necessary also for programming tools such as Prolog Techniques Editor [12]. On the other hand, when teaching novices (especially when very short period o f time is available), very simple set o f schemata should be devised. To speed up learning, ready to use knowledge should be presented to learners. Our program schemata were devised with this point in mind. They are purpously "incomplete" in the sense that their specialization cannot be for some problems completed at the syntactic level. As the main result, we report on experiments that allow to judge quite favorably the approach to 45 teaching Prolog programming when the student learns a set of program schemata and how to apply them. 1. 2. 3. 4. 5. 6. References M. Bielikowi, P. Nfivrat. A schema-based approach to teaching programming in Lisp and Prolog. In: Proc. PEG '97 Int. Conf., P. Brna and D. Dicheva (Eds.), 22-29. 1997. A, Bowles, P. Brna. Programming plans and programming techniques. In Proc. Worm Conf. on AI in Education, P. Brna, S. Ohlsson and H. Pain (Eds.), 378-385. AACE Press, 1993. P. Brna. Teaching Prolog Techniques. Computers and Education, 20(1):111-17. 1993. P. Flenner, K.K. Lau, M. Ornaghi. Correctschema-guided Synthesis of Steadfast Programs. In Proc. 1997 IEEE Conf. on Automated Software Engineering. M. Lowry and Y. Ledru (Eds.), IEEE Press. 1997. T.S. Gegg-Harrison. Representing logic program schemata in ~Prolog. In Proc. of the 12th lnt. Conf. on Logic Programming, L. Sterling (Ed.), 467-481. MIT Press, 1995. T.S. Gegg-Harrison. Extensible logic program schemata. In Proc. of the 6th Int. Conf. on Logic Program Synthesis and Transformation, I. Gaallagher (Ed.). Springer-Verlag, 1996. 7. S.M. Haynes. Explaining recursion to the unsophisticated. SiGSCE Bulletin, 27(3):3-6. 1995. 8. S. Joosten (Ed.), K. van den Berg, G. van der Hoeven. Teaching functional programming to first-year students. J. Functional Programming, 3(1):49-65. January, 1993. 9. P. N~ivrat, V. Rozinajowi. Making programming knowledge explicit. Computers and Education, 21 (4):281-299.1993. 10. C. Sollohub. Programming Templates: Professional programmer knowledge needed by the novice. Computer Science Education, 3:255266. 1991. 11. L.S. Sterling, M. Kirschenbaum. Applying techniques to skeletons. In Constructing Logic Programs, J.M.Jacquet (Ed.), 127-140. John Wiley, 1993. 12. W.W. Vaseoncelos, M. Vargas-Vera, D.S. Robertson. Building Large-Scale Prolog Programs using a Techniques Editing System. In Int. Logic Programming Symposium. The MIT Press. 1993 13. W.W. Vasconcelos, N.E. Fuchs. Prolog Program Development via Enhanced SchemaBased Transformations. In Proc. of 7th Workshop on Logic Programming Environments, Portland, 1995. Appendix - program schemata used in experiments Processing lists at the top level only Processing lists at all levels Map([], []). Map([Hl] Td, [H21T2]) :[Element-Test(Ht),] Transform(Hb H2), Map(Tb T2). [Map([n I Td, [H ]T2] ) :[Not-Element-Test(H),] Map(Tl, T2).] DMap([H, IT,], [H21 T2]) :DMap(Hb H2), DMap(Tb T2). DMap(Eb E2) :Test(El [, E2]), Transform(EbEz). DMap(E, E &l) [:- Not-Test(E &2)]. Func-Reduce([], Neutral-Value). Func-Reduce([HIT], R) :[Element-Test(H ),] Func-Reduce(T, RL), Element-Reduce(H,RL, R). [Func-Reduce([HlT], R) :[Not-Element-Test(H),] Func-Reduce(T,R).] DFunc-Reduce([H IT], R) :DFunc-Reduce(H, RH), DFunc-Reduce(T, RT), Reduction(RH, RT, R). DFunc-Reduce(E, E) :- Test(E). DFunc-Reduce(E, Neutral-Value) [:-Not-Test(E )]. Count-iN[i, 0). DCount-iN[HlT], C) :DCount-iNH, CH), DCount-iNT, CT), C is CH + CT. DCount-iNE, 1) :- Test(E). DCount-iNE, 0) [:- Not-Test(E)]. Count-iN[H IT], C) :Element-Test(H), Count-iNT, CL), C is CL + 1. Count-iN[H IT], C) :[Not-Element-Test(H),] Count-i~T, C). 46 _. Processing Lists at the top level only Processing lists at all levels Count-if-not([], 0). Count-if-not([Ht T], C) :Element-Test(H), Count-if-not(T, C). Count-if-not([HlY], C) :[Not-Element-Test(H),] Count-if-not(T, CL), C is CL + 1. DCount-if-not([H IT], C) :DCount-if-not(H, CH), DCount-if-not(T, CT), DCount-if-not(E, O) :- Test(E). DCount-if-not(E, 1) [:- Not-Test(E)]. Find-iRE, [H I _ ]) :-Element-Test(E, H). Find-~E, [_IT]) :- Find-iRE, T). DFind-i~E, [H IT]) :-DFind-i~E, H) ; DFind-i~E, T). DFind-iflE, H) :- Test(E, H). EveN[I). Every([H I T]) :Element-Test(H), Every(T). DEvery([]). DEvery([H I T]) :- DEvery(H), DEvery(T). DEvery(E) :- Test(E). Some([H [_]) :- Element-Test(H). Some([H [T]) :- [Not-Element-Test(H),] Some(T). DSome([H [ T]) :- DSome(H) ; DSome(T). DSome(E) :- Test(E). None([]). None([H [ T]) :- Element-Test(H), t, fail. None([H l T]) :- [Not-Element-Test(H),] None(T). DNone([H [ T]) :- DNone(H), DNone(T). DNone(E) :- Test(E), !, fail. DNone(E). DSome-not([H [ T]) :- DSome-not(H) ; DSome-not(T). [DSome-not([]) :- t, fail.] DSome-not(E) :- Test(E &2), !, fail. Dsome-not(E). Some-not([H [T]) :- Element-Test(H), Some-not(T). Some-not([H ] _]) [:- Not-Element-Test(H)]. C is CH + CT. Remove-K[], []). Remove-~[H [ T1], T2) :Element-Test(H), Remove-i~T1, T2). Remove-ifl[H IT1], [H [T2]) :[Not-Element-Test(H),] Remove-i~T1, T2 ). DRemove-~[HllTl], R) :DRemove-i~H, H2), DRemove-i~T , T2), combine(H2, Tz, R). DRemove-~E, remove-flag) :- Test(E). DRemove-iflE, E) [:-Not-Test(E)]. Remove-oCnot([], []). Remove-if-not([H[T1], [H [ T2]) :Element- Test(H), Remove-i~T l, "I"2). Remove-i~[H [T1], T2) :[Not-Element-Test(H),] Remove-i~T1, T2). [DRemove-~not([], []).] DRemove-if-not([Hl I Tl], R) :DRemove-if-not(H, H2), DRemove-~not(T , T2), combine(H2, "1"2,R). DRemove-i~not(E, E) :- Test(E). DRemove-if-not(E, remove-flag) [:- Not-Test(E)]. combine(remove-flag, T, T). combine(H, T, [H IT]). 47