## Chapter 3: Recursion Recursive definitions require that the recursive function isn't the first clause, ex: ``` is_digesting(X,Y) :- just_ate(X,Y). is_digesting(X,Y) :- just_ate(X,Z), is_digesting(Z,Y). ``` Recursive definition require a base ("escape") clause in addition to the recursive clause. ### Rule ordering, goal ordering, and termination Underlying vision for Prolog (and logic programming in general): the programmer should be able to describe problems, and the computer derives the solution. The programmer builds a knowledge base, then asks question of the computer. Prolog's search order: 1. KB from top to bottom 2. Clauses from left to right 3. Backtracks on bad choices This is somewhat of a procedural approach to declarative programming which may affect the answer. Compare `descend1` with `descend2`: ``` child(anne,bridget). child(bridget,caroline). child(caroline,donna). child(donna,emily). descend1(X,Y) :- child(X,Y). descend1(X,Y) :- child(X,Z), descend1(Z,Y). descend2(X,Y) :- descend2(Z,Y), child(X,Z). descend2(X,Y) :- child(X,Y). ``` Supposedly these give different answers, but `swipl` exploded on the latter... and continuing reading, that's the point --- a warning to avoid left-recursive rules. The takeaway is that you can get the overall idea of how to write the program by approaching the problem declaratively. Sensible goal orderings ensure program / query termination: place the recursive definition last. ### Exercises #### Exercise 3.1 In the text, we discussed the predicate ``` descend(X,Y) :- child(X,Y). descend(X,Y) :- child(X,Z), descend(Z,Y). ``` Suppose we reformulated this predicate as follows: ``` descend(X,Y) :- child(X,Y). descend(X,Y) :- descend(X,Z), descend(Z,Y). ``` Would this be problematic? **A**: yes: there's no termination clause. See `descend3` in `descend.pl`. #### Exercise 3.2 Do you know these wooden Russian dolls (Matryoshka dolls) where the smaller ones are contained in bigger ones? Ex katarina(olga(natasha(irina))). First, write a knowledge base using the predicate `directlyIn/2` which encodes which doll is directly contained in which other doll. Then, define a recursive predicate `in/2`, that tells us which doll is (directly or indirectly) contained in which other dolls. For example, the query `in(katarina,natasha)` should evaluate to true, while `in(olga, katarina)` should fail. ``` directlyIn(natasha, irina). directlyIn(olga, natasha). directlyIn(katarina, olga). in(X, Y) :- directlyIn(X, Y). in(X, Y) :- directlyIn(X, Z), in(Z, Y). ``` #### Exercise 3.3 We have the following knowledge base: ``` directTrain(saarbruecken,dudweiler). directTrain(forbach,saarbruecken). directTrain(freyming,forbach). directTrain(stAvold,freyming). directTrain(fahlquemont,stAvold). directTrain(metz,fahlquemont). directTrain(nancy,metz). ``` That is, this knowledge base holds facts about towns it is possible to travel between by taking a direct train. But of course, we can travel further by chaining together direct train journeys. Write a recursive predicate `travelFromTo/2` that tells us when we can travel by train between two towns. For example, when given the query `travelFromTo(nancy,saarbruecken)` it should reply yes. ``` travelFromTo(X, Y) :- directTrain(X, Y). travelFromTo(X, Y) :- directTrain(X, Z), travelFromTo(Z, Y). ``` #### Exercise 3.4 Define a predicate `greater_than/2` that takes two numerals in the notation that we introduced in the text (that is, `0`, `succ(0)`, `succ(succ(0))`, and so on) as arguments and decides whether the first one is greater than the second one. For example: ``` ?- greater_than(succ(succ(succ(0))),succ(0)). yes ?- greater_than(succ(succ(0)),succ(succ(succ(0)))). no ``` Answer (in `succ.pl`): ``` greater_than(succ(succ(X)), succ(0)). greater_than(succ(X), succ(Y)) :- greater_than(X, Y). ``` #### Exercise 3.5 Binary trees are trees where all internal nodes have exactly two children. The smallest binary trees consist of only one leaf node. We will represent leaf nodes as `leaf(Label)`. For instance, `leaf(3)` and `leaf(7)` are leaf nodes, and therefore small binary trees. Given two binary trees B1 and B2 we can combine them into one binary tree using the functor `tree/2` as follows: `tree(B1,B2)`. So, from the leaves `leaf(1)` and `leaf(2)` we can build the binary tree `tree(leaf(1),leaf(2))` . And from the binary trees `tree(leaf(1),leaf(2))` and `leaf(4)` we can build the binary tree `tree(tree(leaf(1), leaf(2)),leaf(4))`. Now, define a predicate `swap/2`, which produces the mirror image of the binary tree that is its first argument. For example: ``` ?- swap(tree(tree(leaf(1), leaf(2)), leaf(4)),T). T = tree(leaf(4), tree(leaf(2), leaf(1))). yes ``` This one took a lot of thinking, but the solution is in `tree.pl`.