Background
This homework serves to
introduce you to purely declarative programming in Prolog, while the
next one will introduce you to other parts of Prolog,
including
non-declarative constructs. Homework 10 (i.e., the Prolog
project)
will
be a real application.
Before you Start
If you haven't already done so, install Prolog and go through pages 3-5
of Lu &
Mead to learn how to use the SWI environment (if needed).
Alternatively, you
can go through section 2.1 of the SWI documentation (click on
Documentation, follow the "SWI-Prolog reference manual" link, and click
on the filetab icon on the top). Online help from within
prolog
is also available by typing "help(<predicate>).".
Guidelines
You should write
all
programs as declaratively as possible. If you are unsure
whether
or not something you do is declarative, ask by email.
The stylistic requirements are:
- The only
pre-defined predicates you may use are:
- Arithmetic
- Comparison (excluding
equality)
- Lists: member/2, append/3, length/2
- Control: cut (!), but only when absolutely needed.
For this assignment, I am requiring you to write a comment
documenting why you can't avoid the cut. All of the problems
here can be done without a cut, though you might occasionally
need a cut if you approach the problem differently.
- Programs should work in all specified modes for the first
solution (but not necessarily for additional solutions).
- You should get rid of any warning
messages. The most common warning results from using a named
variable where an anonymous variable would suffice. As
might be expected, ignoring warnings typically lead to problems down
the line.
- All predicates should be documented with modes as discussed
in class.
Common Beginner Errors (read this before you start)
I've listed some common errors below, in no particular order.
It goes without saying that you are not allowed to make these
errors. We haven't covered some of these, but I'm mentioning them
since people seem to find them.
- Using = (or its variants: ==, etc.). Many often
write something like p(X,Y) :- X=Y,q(...). You really mean p(X,X) :-
q(...). More disturbingly, this reflects an imperative style
of thought, treating = as assignment.
- Using if-then-else predicates, or disjunction (;).
These do not do
what you think they do. The same can be said of any
predicates listed as "control predicates" in the SWI documentation.
As a general rule, control predicates are the gotos of logic
programming.
- Using assert/retract. This is Prolog's way to
have side effects, which is of course bad.
- Excessive use of cut.
- Using "not". This suffers from some logical
paradoxes, which we will talk about later.
All of the programs in this problem can be written in a few lines of
code. If you are writing a lot of code, you should probably
rethink your approach. Think declaratively!
It goes without saying that you should test your programs adequately,
including boundary cases. THINK DECLARATIVELY!
Assignment:
Write the following predicates in Prolog. For most
of them, I have given
examples in the <+,+,...+> mode. This
is purely for explanatory
purposes, and your programs should work for all specified modes, except
where otherwise stated.
- atoms_in_list(+List,?AtomList)
succeeds if AtomList is a list of
the elements in a [possibly nested] list, List.
Ex: atoms_in_list([a,1,[3,a,[1,2,3],b],c],[a,1,3,a,1,2,3,b,c])
- Write the Prolog version of interleave from the Haskell homework
earlier this semester (except that it works in all modes). Please use
Prolog naming conventions though.
- Write an interleave2 predicate that is the same as above, except
that it fails if the two lists are of differing lengths. Of course,
there is no longer a Pad argument.
- keyRecord(+DB,?Record,?Key) succeeds if the structure
rec(Key,Record) is in the database DB.
Ex: keyRecord([rec(al,1),rec(bo,2),rec(al,3),rec(ida,4)],3,al)
To think
about: Recall that Prolog's fundamental data
structure is a
structure with uninterpreted functor (in this case, "rec" is a
functor). The word "uninterpreted"
essentially means that it is purely syntactic sugar, and you can not
unify against it -
you might want to try unifying a variable to it (e.g.,
X(b,2) with rec(b,2)) to see what happens.
- canyon(+IntList) succeeds if IntList consists of decreasing
integers followed by increasing
integers. For
example, [11,8,8,5,2,3,7] is a canyon, but [5,4,3,2,1] and
[11,8,8,5,2,3,7,5] are not canyons. You may assume that IntList
contains
only integers.
- canyonInList(+IntList,?Canyon) succeeds if Canyon is a canyon
somewhere in IntList.
- legal(+List) succeeds if List is legal in the language generated
by the start symbol S in the following EBNF grammar:
S --> a{b}S | T | Sb
T --> c | cS
For example, [a,b,b,c,c,b] is legal.
- Identify 3 of your above programs, where each satisfies a
different
one of the following requirements:
- The same program could be written in Haskell almost
identically (excluding minor syntactical differences)
- A Haskell program using the same approach is not
possible due
to the difference between pattern matching and unification
- A Haskell program using the same approach is not
possible due
to some other difference between the logic and functional paradigms.
Explain briefly (1 sentence each), in clearly identified comments.
Submission
The programs should be submitted electronically to the grader, and cc'd
to me. All programs should be in one
file,
named
<firstname>_<surname>_hw8.pl. Make sure you have
documented your code using the
standards
we discussed in class.
Hints/Clarifications/Corrections
- You may have seen (or
written) Prolog elsewhere.
However, our focus here is on declarative
logic programming, and the other code probably does not meet our
requirements.