Seeing if there is a possible train route through Prolog - recursion

A problem I'm working on with Prolog is to see if a train can travel from one destination to the next. There are two rules.
A train can travel through on or more intermediary from one destination to the next.
Ex: San Francisco to Los Angeles
Los Angeles to Irvine
Irvine to San Diego
This gives a route from San Francisco to San Diego.
A train can travel to and from a destination. So if a train can travel from San Francisco to Los Angeles, it can travel from Los Angeles to San Francisco.
This is the code I currently have.
nonStopTrain(sandiego,oceanside).
nonStopTrain(lasvegas,sandiego).
nonStopTrain(sanfrancisco,bakersfield).
nonStopTrain(bakersfield,sandiego).
nonStopTrain(oceanside,losangeles).
nonStopTrain(portland,sanfrancisco).
nonStopTrain(seattle,portland).
canTravel(From, To) :- nonStopTrain(From, To); nonStopTrain(To, From).
canTravel(From, To) :-
canTravel(From, Through), canTravel(Through, To).
The problem is the ability to travel bidirectionally. When I run this program, I keep running back and fourth between the same places, and I'm not exactly sure why.

The problem with a naive solution is that there are an infinite number of ways to get from point A to point B if you don't eliminate cycles. Suppose I want to go from Seattle to San Francisco. Without handling cycles, we're going to get each of these as a unique solution:
seattle -> portland -> seattle -> portland -> sanfrancisco
seattle -> portland -> seattle -> portland -> seattle -> portland -> sanfrancisco
seattle -> (portland -> seattle) x N -> sanfrancisco
There's no limit to the number of times you can double back on yourself, so there's effectively an infinite number of solutions once you have as little as three nodes connected. In practice you don't want any solutions where you double back on yourself, but Prolog doesn't know that and there's no intuitive and naive way to prevent it.
One of the better ways forward is to simply keep track of where you've been. To do that we're going to need to make the predicate take an extra argument. First I've also introduced a helper predicate.
connectedDirectly(From, To) :- nonStopTrain(From, To) ; nonStopTrain(To, From).
Having this separated out will reduce the desire to call canTravel recursively when we really just want to attach one more leg to the journey. Now for canTravel:
canTravel(From, To) :- canTravel(From, To, []).
This is an arity 2 rule that maps onto our new arity 3 rule. The list of places we've been is always empty initially. Now we need a base case:
canTravel(From, To, _) :- connectedDirectly(From, To).
This should be obvious. Now the inductive case is a little different, because we need to do two things: find a new leg to attach to the journey, make sure we haven't been through that leg before, and then recur, adding the new leg to the list of places we've been. Finally, we want to ensure we don't get large cycles where we end up where we started, so we add a rule to the end to make sure we don't.
canTravel(From, To, Visited) :-
connectedDirectly(From, Through),
\+ memberchk(Through, Visited),
canTravel(Through, To, [Through|Visited]),
From \= To.
Now if you run it you'll find you get 98 solutions and all the solutions are symmetric:
?- forall(canTravel(X, Y), (write(X-Y), nl)).
sandiego-oceanside
lasvegas-sandiego
sanfrancisco-bakersfield
... etc.
So, happily, we were able to avoid going for a breadth-first search solution.
Edit
I have apparently confused the situation by overloading the name canTravel for two separate predicates. In Prolog, a predicate is uniquely defined by the name and the arity, much like overloading in C++ or Java where the "effective method" is determined by the number of arguments and the name, not just the name.
Your intuition is correct—the empty list in canTravel(From, To) :- canTravel(From, To, []) is establishing an initial binding for the list of visited places. It's not exactly allocating storage so much as establishing a base case.
There are really two uses of canTravel inside itself. One of them is calling canTravel/3 from canTravel/2. In this case, canTravel/3 is really sort of like a helper, doing the actual work of canTravel/2, but with an internal variable that we are initializing to the empty list. The other use is canTravel/3 from within canTravel/3, and for that we're both using it to achieve the same goal: recursion, Prolog's primary "looping" construction.
The third argument in canTravel(From, To, _) :- connectedDirectly(From, To) is what makes this clause part of canTravel/3. This is the base case of the recursion, so it doesn't need to consider the places we've visited so far (although the inductive case will prevent a circular journey). We could also check it here, but it turns out to be more expensive and have no effect on the resultset:
canTravel(From, To, Visited) :- connectedDirectly(From, To), \+ memberchk(To, Visited).
I concluded that if it was adding expense and complexity without changing the answers we could omit the check, which reduces the base case to the original one with the anonymous third variable.
It may make more sense to see this without the overloading, in which case it looks like this:
canTravel(From, To) :- canTravel_loop(From, To, []).
canTravel_loop(From, To, _) :- connectedDirectly(From, To).
canTravel_loop(From, To, Visited) :-
connectedDirectly(From, Through),
\+ memberchk(Through, Visited),
canTravel_loop(Through, To, [Through|Visited]),
From \= To.
Edit 2
Regarding the "bar operator," your intuition is once again correct. :) I'm using it here to prepend an item to a list. What's confusing you is that in Prolog, with unification, most expressions express relationships rather than procedures. So depending on the context, [X|Xs] might be used to construct a new list (if you have X and XS in hand) or it might be used to break an implicit list into a head X and tail Xs. Look at all the ways I can use it just from the repl:
?- X = hello, Xs = [world, new, user], Y = [X|Xs].
Y = [hello, world, new, user].
This is basically how we're using it in canTravel: we have Through and we have Visited, so we're making a new list with Through first and Visited as the tail, and that's the third parameter to the recursive invocation. In procedural terms, we're just adding Through to a variable we're using in our loop.
But because this is Prolog, we're not limited to using things in one direction:
?- Y = [hello, world, new, user], Y = [X|Xs].
X = hello,
Xs = [world, new, user].
?- Y = [hello, world, new, user], [X|Xs] = Y.
X = hello,
Xs = [world, new, user].
Notice that Prolog didn't care which direction the assignment happened in, but it managed to "work backwards" to figure out what X and Xs should be using Y. This is one of the magical things about Prolog. (Note that in the examples in this session I'm omitting the variables which are echoed back because they obscure the point.)
In general, you want predicates that can solve for different parameters. For instance, member/2 can be used to test membership or to enumerate items. append/3 can build a new list from two old lists, or it can enumerate all the ways to split a list into two segments, or it can find a prefix or suffix given a list and a suffix or prefix.
As you get more used to this functionality you'll stop thinking of Prolog rules as being like functions in other languages and start to see them as relations: logical "truths" that exist between certain constructions. member/2 isn't written by trying to enumerate items or by seeking through a list looking for a particular value. It's implemented by saying: the relation member(Item, List) is true when the Item is the first thing in List:
member(Item, [Item|_]).
or else when Item is in the remainder of the list:
member(Item, [_|Tail]) :- member(Item, Tail).
This definition is sufficient for all the possible uses. If Item is not instantiated, it will be instantiated to the first item in the list, then the first item in the tail of that list, and so on. If Item is instantiated, it will be true if Item is the first item in the list or if it is the first item in the tail. Surprisingly, member/2 can even be used to generate lists that contain a value:
?- member(1, X).
X = [1|_G274] ;
X = [_G8, 1|_G12] ;
X = [_G8, _G11, 1|_G15] .
You can see what happened there: the _ in the second clause is being made into anonymous variables, so it's generating lists with the 1 in the first position, then the second, then the third, etc.
A lot of Prolog works like this. This one is also pretty surprising:
?- length(X, 3).
X = [_G273, _G276, _G279].
Hope this helps clarify things a bit more! :)

Do you have use some specific Prolog system?
Your program will work as intended without modifications (well, you have to add :- auto_table. as a first line of your program) in a system with tabling support, like B-Prolog.

I think adding a cut will stop your infinite recursion issue because once it finds an answer it won't keep backtracking forever:
canTravel(From, To) :- nonStopTrain(From, To); nonStopTrain(To, From).
canTravel(From, To) :-
canTravel(From, Through), canTravel(Through, To), !.
I have no doubt that there is a more correct solution than this though.

Related

Prolog recursive accumulator

I am trying to make a knowledge base for college courses. Specifically, right now I am trying to make an accumulator that will take a course and provide a list of all classes that must be taken first, i.e. The course's prereqs, the prereqs to those prereqs, etc... Based on this chart.
Here is a sample of the predicates:
prereq(cst250, cst126).
prereq(cst223, cst126).
prereq(cst126, cst116).
prereq(cst105, cst102).
prereq(cst250, cst130).
prereq(cst131, cst130).
prereq(cst130, cst162).
prereq(anth452, wri122).
prereq(hist452, wri122).
And here is my attempt at an accumulator:
prereq_chain(Course, PrereqChain):-
%Get the list of prereqs for Course
findall(Prereq, prereq(Course, Prereq), Prereqs),
%Recursive call to all prereqs in X
forall(member(X, Prereqs),
(prereq_chain(X, Y),
%Combine current layer prereqs with deeper
append(Prereqs, Y, Z))),
%Return PrereqChain
PrereqChain = Z.
The desired output from a query would be:
?- prereq_chain(cst250, PrereqList).
PrereqList = [cst116, cst126, cst162, cst130]
Instead, I get an answer of true, and a warning about Z being a singleton.
I have looked at other posts asking on similar issues, but they all had a single lane of backward traversal, whereas my solution requires multiple lanes.
Thanks in advance for any guidance.
The problem with using forall/2 is that it does not establish bindings. Look at this contrived example:
?- forall(member(X, [1,2,3]), append(['hi'], X, R)).
true.
If a binding were established for X or R by the forall/2, it would appear in the result; instead we just got true because it succeeded. So you need to use a construct that doesn't just run some computation but something that will produce a value. The thing you want in this case is maplist/3, which takes a goal and a list of parameters and builds a larger goal, giving you back the results. You will be able to see the effect in your console after you put in the solution below.
?- maplist(prereq_chain, [cst126, cst130], X).
X = [[cst116], [cst162]].
So this went and got the list of prerequisites for the two classes in the list, but gave us back a list of lists. This is where append/2 comes in handy, because it essentially flattens a list of lists:
?- append([[cst116], [cst162]], X).
X = [cst116, cst162].
Here's the solution I came up with:
prereq_chain(Class, Prereqs) :-
findall(Prereq, prereq(Class, Prereq), TopPrereqs),
maplist(prereq_chain, TopPrereqs, MorePrereqs),
append([TopPrereqs|MorePrereqs], Prereqs).

Avoiding infinite recursion but still using unbound parameter passing only

I have the following working program: (It can be tested on this site: http://swish.swi-prolog.org, I've removed the direct link to a saved program, because I noticed that anybody can edit it.)
It searches for a path between two points in an undirected graph. The important part is that the result is returned in the scope of the "main" predicate. (In the Track variable)
edge(a, b).
edge(b, c).
edge(d, b).
edge(d, e).
edge(v, w).
connected(Y, X) :-
(
edge(X, Y);
edge(Y, X)
).
path(X, X, _, []) :-
connected(X, _).
path(X, Y, _, [X, Y]) :-
connected(Y, X).
path(X, Z, Visited, [X|Track]) :-
connected(X, Y),
not(member(X, Visited)),
path(Y, Z, [X|Visited], Track).
main(X, Y) :-
path(X, Y, [], Track),
print(Track),
!.
Results:
?- main(a, e).
[a, b, d, e]
true
?- main(c, c).
[]
true
?- main(b, w).
false
My questions:
The list of visited nodes is passed down to the predicates in 2 different ways. In the bound Visited variable and in the unbound Track variable. What are the names of these 2 different forms of parameter passing?
Normally I only wanted to use the unbound parameter passing (Track variable), to have the results in the scope of the main predicate. But I had to add the Visited variable too, because the member checking didn't work on the Track variable (I don't know why). Is it possible to make it work with only passing the Track in an unbound way? (without the Visited variable)
Many thanks!
The short answer: no, you cannot avoid the extra argument without making everything much messier. This is because this particular algorithm for finding a path needs to keep a state; basically, your extra argument is your state.
There might be other ways to keep a state, like using a global, mutable variable, or dynamically changing the Prolog data base, but both are more difficult to get right and will involve more code.
This extra argument is often called an accumulator, because it accumulates something as you go down the proof tree. The simplest example would be traversing a list:
foo([]).
foo([X|Xs]) :-
foo(Xs).
This is fine, unless you need to know what elements you have already seen before getting here:
bar(List) :-
bar_(List, []).
bar_([], _).
bar_([X|Xs], Acc) :-
/* Acc is a list of all elements so far */
bar_(Xs, [X|Acc]).
This is about the same as what you are doing in your code. And if you look at this in particular:
path(X, Z, Visited, /* here */[X|Track]) :-
connected(X, Y),
not(member(X, Visited)),
path(Y, Z, [X|Visited], /* and here */Track).
The last argument of path/4 has one element more at a depth of one less in the proof tree! And, of course, the third argument is one longer (it grows as you go down the proof tree).
For example, you can reverse a list by adding another argument to the silly bar predicate above:
list_reverse(L, R) :-
list_reverse_(L, [], R).
list_reverse_([], R, R).
list_reverse_([X|Xs], R0, R) :-
list_reverse_(Xs, [X|R0], R).
I am not aware of any special name for the last argument, the one that is free at the beginning and holds the solution at the end. In some cases it could be an output argument, because it is meant to capture the output, after transforming the input somehow. There are many cases where it is better to avoid thinking about arguments as strictly input or output arguments. For example, length/2:
?- length([a,b], N).
N = 2.
?- length(L, 3).
L = [_2092, _2098, _2104].
?- length(L, N).
L = [],
N = 0 ;
L = [_2122],
N = 1 ;
L = [_2122, _2128],
N = 2 . % and so on
Note: there are quite a few minor issues with your code that are not critical, and giving that much advice is not a good idea on Stackoverflow. If you want you could submit this as a question on Code Review.
Edit: you should definitely study this question.
I also provided a somewhat simpler solution here. Note the use of term_expansion/2 for making directed edges from undirected edges at compile time. More important: you don't need the main, just call the predicate you want from the top level. When you drop the cut, you will get all possible solutions when one or both of your From and To arguments are free variables.

Erlang Recursive end loop

I just started learning Erlang and since I found out there is no for loop I tried recreating one with recursion:
display(Rooms, In) ->
Room = array:get(In, Rooms)
io:format("~w", [Room]),
if
In < 59 -> display(Rooms, In + 1);
true -> true
end.
With this code i need to display the content (false or true) of each array in Rooms till the number 59 is reached. However this creates a weird code which displays all of Rooms contents about 60 times (?). When I drop the if statement and only put in the recursive code it is working except for a exception error: Bad Argument.
So basically my question is how do I put a proper end to my "for loop".
Thanks in advance!
Hmm, this code is rewritten and not pasted. It is missing colon after Room = array:get(In, Rooms). The Bad argument error is probably this:
exception error: bad argument
in function array:get/2 (array.erl, line 633)
in call from your_module_name:display/2
This means, that you called array:get/2 with bad arguments: either Rooms is not an array or you used index out of range. The second one is more likely the cause. You are checking if:
In < 59
and then calling display again, so it will get to 58, evaluate to true and call:
display(Rooms, 59)
which is too much.
There is also couple of other things:
In io:format/2 it is usually better to use ~p instead of ~w. It does exactly the same, but with pretty printing, so it is easier to read.
In Erlang if is unnatural, because it evaluates guards and one of them has to match or you get error... It is just really weird.
case is much more readable:
case In < 59 of
false -> do_something();
true -> ok
end
In case you usually write something, that always matches:
case Something of
{One, Two} -> do_stuff(One, Two);
[Head, RestOfList] -> do_other_stuff(Head, RestOfList);
_ -> none_of_the_previous_matched()
end
The underscore is really useful in pattern matching.
In functional languages you should never worry about details like indexes! Array module has map function, which takes function and array as arguments and calls the given function on each array element.
So you can write your code this way:
display(Rooms) ->
DisplayRoom = fun(Index, Room) -> io:format("~p ~p~n", [Index, Room]) end,
array:map(DisplayRoom, Rooms).
This isn't perfect though, because apart from calling the io:format/2 and displaying the contents, it will also construct new array. io:format returns atom ok after completion, so you will get array of 58 ok atoms. There is also array:foldl/3, which doesn't have that problem.
If you don't have to have random access, it would be best to simply use lists.
Rooms = lists:duplicate(58, false),
DisplayRoom = fun(Room) -> io:format("~p~n", [Room]) end,
lists:foreach(DisplayRoom, Rooms)
If you are not comfortable with higher order functions. Lists allow you to easily write recursive algorithms with function clauses:
display([]) -> % always start with base case, where you don't need recursion
ok; % you have to return something
display([Room | RestRooms]) -> % pattern match on list splitting it to first element and tail
io:format("~p~n", [Room]), % do something with first element
display(RestRooms). % recursive call on rest (RestRooms is quite funny name :D)
To summarize - don't write forloops in Erlang :)
This is a general misunderstanding of recursive loop definitions. What you are trying to check for is called the "base condition" or "base case". This is easiest to deal with by matching:
display(0, _) ->
ok;
display(In, Rooms) ->
Room = array:get(In, Rooms)
io:format("~w~n", [Room]),
display(In - 1, Rooms).
This is, however, rather unidiomatic. Instead of using a hand-made recursive function, something like a fold or map is more common.
Going a step beyond that, though, most folks would probably have chosen to represent the rooms as a set or list, and iterated over it using list operations. When hand-written the "base case" would be an empty list instead of a 0:
display([]) ->
ok;
display([Room | Rooms]) ->
io:format("~w~n", [Room]),
display(Rooms).
Which would have been avoided in favor, once again, of a list operation like foreach:
display(Rooms) ->
lists:foreach(fun(Room) -> io:format("~w~n", [Room]) end, Rooms).
Some folks really dislike reading lambdas in-line this way. (In this case I find it readable, but the larger they get the more likely the are to become genuinely distracting.) An alternative representation of the exact same function:
display(Rooms) ->
Display = fun(Room) -> io:format("~w~n", [Room]) end,
lists:foreach(Display, Rooms).
Which might itself be passed up in favor of using a list comprehension as a shorthand for iteration:
_ = [io:format("~w~n", [Room]) | Room <- Rooms].
When only trying to get a side effect, though, I really think that lists:foreach/2 is the best choice for semantic reasons.
I think part of the difficulty you are experiencing is that you have chosen to use a rather unusual structure as your base data for your first Erlang program that does anything (arrays are not used very often, and are not very idiomatic in functional languages). Try working with lists a bit first -- its not scary -- and some of the idioms and other code examples and general discussions about list processing and functional programming will make more sense.
Wait! There's more...
I didn't deal with the case where you have an irregular room layout. The assumption was always that everything was laid out in a nice even grid -- which is never the case when you get into the really interesting stuff (either because the map is irregular or because the topology is interesting).
The main difference here is that instead of simply carrying a list of [Room] where each Room value is a single value representing the Room's state, you would wrap the state value of the room in a tuple which also contained some extra data about that state such as its location or coordinates, name, etc. (You know, "metadata" -- which is such an overloaded, buzz-laden term today that I hate saying it.)
Let's say we need to maintain coordinates in a three-dimensional space in which the rooms reside, and that each room has a list of occupants. In the case of the array we would have divided the array by the dimensions of the layout. A 10*10*10 space would have an array index from 0 to 999, and each location would be found by an operation similar to
locate({X, Y, Z}) -> (1 * X) + (10 * Y) + (100 * Z).
and the value of each Room would be [Occupant1, occupant2, ...].
It would be a real annoyance to define such an array and then mark arbitrarily large regions of it as "unusable" to give the impression of irregular layout, and then work around that trying to simulate a 3D universe.
Instead we could use a list (or something like a list) to represent the set of rooms, but the Room value would now be a tuple: Room = {{X, Y, Z}, [Occupants]}. You may have an additional element (or ten!), like the "name" of the room or some other status information or whatever, but the coordinates are the most certain real identity you're likely to get. To get the room status you would do the same as before, but mark what element you are looking at:
display(Rooms) ->
Display =
fun({ID, Occupants}) ->
io:format("ID ~p: Occupants ~p~n", [ID, Occupants])
end,
lists:foreach(Display, Rooms).
To do anything more interesting than printing sequentially, you could replace the internals of Display with a function that uses the coordinates to plot the room on a chart, check for empty or full lists of Occupants (use pattern matching, don't do it procedurally!), or whatever else you might dream up.

Prolog Accumulators. Are they really a "different" concept?

I am learning Prolog under my Artificial Intelligence Lab, from the source Learn Prolog Now!.
In the 5th Chapter we come to learn about Accumulators. And as an example, these two code snippets are given.
To Find the Length of a List
without accumulators:
len([],0).
len([_|T],N) :- len(T,X), N is X+1.
with accumulators:
accLen([_|T],A,L) :- Anew is A+1, accLen(T,Anew,L).
accLen([],A,A).
I am unable to understand, how the two snippets are conceptually different? What exactly an accumulator is doing different? And what are the benefits?
Accumulators sound like intermediate variables. (Correct me if I am wrong.) And I had already used them in my programs up till now, so is it really that big a concept?
When you give something a name, it suddenly becomes more real than it used to be. Discussing something can now be done by simply using the name of the concept. Without getting any more philosophical, no, there is nothing special about accumulators, but they are useful.
In practice, going through a list without an accumulator:
foo([]).
foo([H|T]) :-
foo(T).
The head of the list is left behind, and cannot be accessed by the recursive call. At each level of recursion you only see what is left of the list.
Using an accumulator:
bar([], _Acc).
bar([H|T], Acc) :-
bar(T, [H|Acc]).
At every recursive step, you have the remaining list and all the elements you have gone through. In your len/3 example, you only keep the count, not the actual elements, as this is all you need.
Some predicates (like len/3) can be made tail-recursive with accumulators: you don't need to wait for the end of your input (exhaust all elements of the list) to do the actual work, instead doing it incrementally as you get the input. Prolog doesn't have to leave values on the stack and can do tail-call optimization for you.
Search algorithms that need to know the "path so far" (or any algorithm that needs to have a state) use a more general form of the same technique, by providing an "intermediate result" to the recursive call. A run-length encoder, for example, could be defined as:
rle([], []).
rle([First|Rest],Encoded):-
rle_1(Rest, First, 1, Encoded).
rle_1([], Last, N, [Last-N]).
rle_1([H|T], Prev, N, Encoded) :-
( dif(H, Prev)
-> Encoded = [Prev-N|Rest],
rle_1(T, H, 1, Rest)
; succ(N, N1),
rle_1(T, H, N1, Encoded)
).
Hope that helps.
TL;DR: yes, they are.
Imagine you are to go from a city A on the left to a city B on the right, and you want to know the distance between the two in advance. How are you to achieve this?
A mathematician in such a position employs magic known as structural recursion. He says to himself, what if I'll send my own copy one step closer towards the city B, and ask it of its distance to the city? I will then add 1 to its result, after receiving it from my copy, since I have sent it one step closer towards the city, and will know my answer without having moved an inch! Of course if I am already at the city gates, I won't send any copies of me anywhere since I'll know that the distance is 0 - without having moved an inch!
And how do I know that my copy-of-me will succeed? Simply because he will follow the same exact rules, while starting from a point closer to our destination. Whatever value my answer will be, his will be one less, and only a finite number of copies of us will be called into action - because the distance between the cities is finite. So the total operation is certain to complete in a finite amount of time and I will get my answer. Because getting your answer after an infinite time has passed, is not getting it at all - ever.
And now, having found out his answer in advance, our cautious magician mathematician is ready to embark on his safe (now!) journey.
But that of course wasn't magic at all - it's all being a dirty trick! He didn't find out the answer in advance out of thin air - he has sent out the whole stack of others to find it for him. The grueling work had to be done after all, he just pretended not to be aware of it. The distance was traveled. Moreover, the distance back had to be traveled too, for each copy to tell their result to their master, the result being actually created on the way back from the destination. All this before our fake magician had ever started walking himself. How's that for a team effort. For him it could seem like a sweet deal. But overall...
So that's how the magician mathematician thinks. But his dual the brave traveler just goes on a journey, and counts his steps along the way, adding 1 to the current steps counter on each step, before the rest of his actual journey. There's no pretense anymore. The journey may be finite, or it may be infinite - he has no way of knowing upfront. But at each point along his route, and hence when ⁄ if he arrives at the city B gates too, he will know his distance traveled so far. And he certainly won't have to go back all the way to the beginning of the road to tell himself the result.
And that's the difference between the structural recursion of the first, and tail recursion with accumulator ⁄ tail recursion modulo cons ⁄ corecursion employed by the second. The knowledge of the first is built on the way back from the goal; of the second - on the way forth from the starting point, towards the goal. The journey is the destination.
see also:
Technical Report TR19: Unwinding Structured Recursions into Iterations. Daniel P. Friedman and David S. Wise (Dec 1974).
What are the practical implications of all this, you ask? Why, imagine our friend the magician mathematician needs to boil some eggs. He has a pot; a faucet; a hot plate; and some eggs. What is he to do?
Well, it's easy - he'll just put eggs into the pot, add some water from the faucet into it and will put it on the hot plate.
And what if he's already given a pot with eggs and water in it? Why, it's even easier to him - he'll just take the eggs out, pour out the water, and will end up with the problem he already knows how to solve! Pure magic, isn't it!
Before we laugh at the poor chap, we mustn't forget the tale of the centipede. Sometimes ignorance is bliss. But when the required knowledge is simple and "one-dimensional" like the distance here, it'd be a crime to pretend to have no memory at all.
accumulators are intermediate variables, and are an important (read basic) topic in Prolog because allow reversing the information flow of some fundamental algorithm, with important consequences for the efficiency of the program.
Take reversing a list as example
nrev([],[]).
nrev([H|T], R) :- nrev(T, S), append(S, [H], R).
rev(L, R) :- rev(L, [], R).
rev([], R, R).
rev([H|T], C, R) :- rev(T, [H|C], R).
nrev/2 (naive reverse) it's O(N^2), where N is list length, while rev/2 it's O(N).

Simple Recursion?

I'm new to programming and have had a hard time understanding recursion. There's a problem I've been working on but can't figure out. I really just don't understand how they are solvable.
"Define a procedure plus that takes two non-negative integers and returns their sum. The only procedures (other than recursive calls to plus) that you may use are: zero?, sub1, and add1.
I know that this is a built in functions in scheme, so I know they're possible to solve, I just don't understand how. Recursion is so tricky!
Any help would be greatly appreciated!
=] Thanks
I'm working in Petite Chez Scheme (with the SWL editor)
Recursion is a very important concept in software development. I don't know (petit chez) scheme so I will approach this from a general angle.
The concept of a recursive function is to repeat the same task over and over again until you reach some limiting boundary. Taking your first question, you have two numbers and you need to add them together. However, you only have the ability to add 1 to a number or subtract 1 from a number. You also have the literal value zero.
So. consider you numbers as two buckets. They each have 10 stones in them. You want to "add" those two buckets together. You are only permitted to move one stone at a time (i.e. you can't grab a handful or tip one bucket into the other).
Lets say you want to move everything from the left bucket into the right bucket, one stone at a time. What are you going to have to do?
First, you have to take 1 stone from the left bucket, i.e. you are using sub1 to remove one stone from the bucket. You then add that same stone to the right bucket, i.e. you add1 to the right bucket.
Now you could do this in a loop, but you don't know how many stones there will be in any given solution. What you really want to do is say "Take one stone from the left bucket, put it in the right bucket and repeat until there are no stones in the left bucket.' This case of there being no stones in the left bucket is called you "Base Case". It's the point at which you say OK, I'm done now.
A pseudocode example of this situation would be (using your plus, add1, sub1 and zero):
plus(leftBucket, rightBucket)
{
if(leftBucket == zero) // check if the left bucket is empty yet
{
// the left bucket is empty, we've moved all the stones
return rightBucket; // the right bucket must be full
}
else
{
// we still have stones in the left bucket, remove 1,
// put it in the right bucket, repeat.
return plus(sub1(leftBucket), add1(rightBucket));
}
}
If you still need more help, let me know, I can run through other examples but this looks like it's probably a homework problem for you and recursion is incredibly important to understand so I don't want to just give you all the answers.
Recursion is simply a function that calls itself. The most common, easily understood examples of recursion is walking a data structure that looks like a tree.
How would you visit each branch of a tree? You would start at the trunk and call visit(branch), passing the trunk of the tree as the first branch. Visit() calls itself for each branch of each branch, and so on.
public void visit(Branch branch)
{
// do something with this branch here
// visit the branches of this branch
foreach(var subbranch in branch.branches)
{
visit(subbranch)
}
}
Recursion is closely related to induction - first you solve (or prove) a base case, and then you assume your solution is correct for some value n, and use that to solve (or prove) it for n + 1.
So the first step here is to look at the first problem. What would be a good base case for adding two numbers together?
Alright, so we have our base case: when one of the numbers is zero.
For simplicity's sake, we'll assume that the second number is zero, just to make things a little easier.
So we know that (+ n 0) is equal to n. So now for our recursive step, we want to take an arbitrary call (+ x y), and turn that into a call which is closer to our ideal (+ n 0). That way we'll have made some progress and will eventually solve our problem.
So how are we going to do this?
(+ x y) is of course equivalent to (+ (add1 x) (sub1 y)) - which takes us closer to our base case of (zero? y).
This gives us our final solution:
(define (+ x y)
(if (zero? y)
(x)
(+ (add1 x) (sub1 y))
))
(you can, of course, swap the order of the arguments and it will still be equivalent).
A similar mechanism can be used to solve the other two problems.

Resources