Starbeamrainbowlabs

Stardust
Blog

Learning Prolog: Lab #7

The new learning prolog banner!

Today's lab introduced lists, and they are a lot harder to comprehend than the other things that we have done so far. You can define a list in Prolog with square brackets, like so:

?- Sandwiches = [ cheese, chicken, cucumber, lettuce_and_tomato ].

This isn't particularly useful, but the real fun comes later on after you've written a bunch of utility rules. Before I get into that though, I should explain a little bit about heads and tails. In Prolog, you can split a list up into its head and its tail with a bar character (|), like so:

printhead([ Head | Tail ]) :-
    write(head).

Here's a quick example of the above in action:

?- printhead([ apple, orange, grape ]).
apple
true.

This is especially useful for recursion, as we shall see in a moment. With that out of the way, here are few utility rules that I put together. There's one that writes out all the items in a list, one that counts up all the numbers in a list, one to concatenate two lists together, and one to calculate the length of a list. They all use loops, so if you don't understand those you should go back and read my previous blog post before continuing.

writelist([]). % Stopping condition.
writelist([ Head | Tail ]) :-
    % Write out the head of the list.
    write(' - '), write(Head), nl,
    % Recursively write out the rest of the list.
    writelist(Tail).

concat([], List, List). % Stopping condition - The 2nd list and the result should be one and the same
% Add the head of the first list onto the result
concat([ Head | Tail ], List2, [ Head | Result ]) :-
    % Recursively add the next item in the first list to the result
    concat(Tail, List2, Result).

countlist([ LastItem | [] ], LastItem). % Stopping condition - Don't continue if we reach the end of the list.
countlist([ Head | Rest ], Result) :-
    % Recursively count the rest of the list
    countlist(Rest, RecursiveResult),
    % Add the head to the result from recursively counting the rest of the list.
    Result is RecursiveResult + Head.

listlength([ _ | [] ], 1).
listlength([ _ | Tail ], Result) :-
    listlength(Tail, RecursiveResult),
    Result is RecursiveResult + 1.

All of the above use a similar loop structure. They recursively sort out the tail, and then deal with the tail when we coming back out again. Here are some examples of the above rules (virtual cookie for whoever works out what all the things in each of the lists below have in common). Don't forget to ask questions in the comments if you don't understand something.

?- writelist([ cat, dog, parrot, elephant, whale]).
- cat
- dog
- parrot
- elephant
- whale
true
?- countlist([ 4, 7, 2, 18, 48, 364 ], Result).
Result = 443 .
?- listlength([ alpha_centauri, sirius, barnards_star, epsilon_eridani, tau_ceti], Length).
Length = 5 .
?- concat([elysium_mons, arsia_mons, aeolis_mons], [skadi_mons, maat_mons], Result).
Result = [elysium_mons, arsia_mons, aeolis_mons, skadi_mons, maat_mons].

Find all the things!

The other thing we looked at this week was the findall/3 predicate. In a nutshell, findall will find everything that matches the given criteria and put them in a list. Here's a simple example:

loves(cat, milk).
loves(dog, bone).
loves(mouse, cheese).
loves(mouse, seeds).
loves(cat, cheese). % Yes, my cat does love cheese...!
loves(parrot, seeds).
?- findall(Who, loves(Who, cheese), Result), writelist(Result).
 - mouse
 - cat
true.

In the above example, we ask Prolog to find us everyone who loves cheese, and then print out the result. The second argument is the criteria we want Prolog to use when searching, the first argument is the variable from the criteria that we want to store, and the third argument is the list we want populating.

As an exercise, try to work out how to ask Prolog who likes seeds, given the above dataset. If you find that easy, try asking Prolog to list everyone who likes both seeds and cheese. The answers will be in the comments.

findall can be used to search many different datasets. Here's another more complicated example:

isa(polly, parrot).
isa(parrot, bird).
isa(bird, living_thing).
hasa(parrot, wings(2)).
hasa(polly, perch).
hasa(polly, colour(green)).
?- findall(green_birds(Who), hasa(Who, colour(green)), Result).
Result = [green_birds(polly)] .

That concludes this blog post on the 7th Prolog lab. If you are interested, here are some links to the source code for the examples found in this post, along with a few extras.

Tag Cloud

3d account algorithms announcement archives arduino artificial intelligence assembly async audio bash batch blog bookmarklet booting c sharp c++ challenge chrome os code codepen coding conundrums coding conundrums evolved command line compiling css dailyprogrammer debugging demystification distributed computing downtime embedded systems encryption es6 features event experiment external first impressions future game github github gist graphics hardware meetup holiday html html5 html5 canvas interfaces internet io.js jabber javascript js bin labs learning library linux low level lua maintenance network networking node.js operating systems performance photos php pixelbot portable privacy programming problems project projects prolog protocol pseudo 3d python reddit reference release releases resource review rust secrets security series list server servers software sorting source code control svg technical terminal textures three thing game three.js tool tutorial twitter ubuntu university update upgrade version control visual web website windows windows 10 xmpp

Archive

Art by Mythdael