So simple (in C,Java,etc,etc) but yet
so hard (in PROLOG)
Magic Squares. For those that dont know what one
is well here is a definition I grabbed off the
net:
"A magic square is an arrangement of the numbers from
1 to n^2 (n-squared) in an nxn matrix, with each number
occurring exactly once, and such that the sum of the
entries of any row, any column, or any main diagonal is
the same. It is not hard to show that this
sum must be n(n^2+1)/2."
Examples (used code below to create):
order of 3 order of 5
8 1 6 17 24 1 8 15
3 5 7 23 5 7 14 16
4 9 2 4 6 13 20 22
10 12 19 21 3
11 18 25 2 9
The code below (in C) will create these magic squares
of the odd numbers.
void odd_num(int n) {
int i,j,num=1;
int nn=n*3/2;
for(i=0; i < n; i++)
for(j=0; j < n; j++)
m[(j-i+nn)%n][(i*2-j+n)%n]=num++;
}
Well basically my question is, in Prolog, how is it
(or it is) possible to have an two demensional array
m[int][int] and then be able to input numbers into this
array? i.e in "random" spots
From my prolog experience I dont think this is possible
is it?
I can see how I could use recursion to do the for loops
but once i go to pop in the number I'm stuck.
Thanks for any help again
Alex
for a two-dimensional array of n x m you could use a functor
with arity n, and then you let each argument be a term with functor m;
accessing then needs two arg/3 operations.
E.g.: 3x3 array: f(f(_,_,_),f(_,_,_),f(_,_,_)).
A generic access predicate for twodimensional `arrays':
access(X,Y,Term,Arg) :-
arg(X,Term,Ys),
arg(Y,Ys,Arg).
It gets more complicated if you need to be able to alter values as
well.
--
Gertjan van Noord Alfa-informatica, RUG, Postbus 716, 9700 AS Groningen
vannoord at let dot rug dot nl http://www.let.rug.nl/~vannoord/
Wow, I havent heard of functor before, or anything your
talking about ;o)
Its hard to me to learn Prolog, cause I do not have a good
book (any book for that matter). I am relying on internet
sites to help me through it.
I'll *try* to figure that stuff out :o)
Thanks
Alex
Okay, starting to narrow things down.
Here's what I have/know now.
If I have
f(f(1,2,3),f(4,5,6),f(7,8,9)).
I can use:
show(A,B,C) :- f(A,B,C).
to show the values like so:
?- show(A,B,C).
A = f(1, 2, 3)
B = f(4, 5, 6)
C = f(7, 8, 9)
Yes
?-
Okay, so thats perfect.
But I still have one problem, which is getting values
into the functor.
Going back to my original problem of the magic squares.
I still dont know how to get values INTO the 'array'.
Like, how do I start with a empty 3x3 array and place
values into it, say put 1 into f(1,2) and 5 into
f(3,2) and so on. Using my formula to calculate where
the values for the magic square go.
Could I have something like this:
magic(N, f(f(_,_,_),f(_,_,_),f(_,_,_))) :- A = 5, B=1,C=2,
insert( A , f, B, C).
% insert 5 into f(1,2) like
% f(f(_,5,_),f(_,_,_),f(_,_,_))
insert(A, f, B, C) :- I dont even know where to start
So then my magic sqaures would look something like this:
/*************************************************/
/* C code of what I want to accomplish */
/* */
/* void odd_num(int n) { */
/* int i,j,num=1; */
/* int nn=n*3/2; */
/* for(i=0; i < n; i++) */
/* for(j=0; j < n; j++) */
/* m[(j-i+nn)%n][(i*2-j+n)%n]=num++; */
/* } */
/*************************************************/
magic(N , f) :- NN is (N*3/2),
Num is Num+1,
I <= N,
I is I+1,
J <= N,
J is J+1,
magic(N,f), % to do first loop
magic(N,f), % to do second loop
S1 is ((j-i+nn) mod n),
S2 is ((i*2-j+n) mod n),
insert(Num, f, S1, S2).
Thats my basic idea. I know it dont work :o(
Also what is mod (remainder) in prolog?
Damn, the more I think the more questions
Thanks
Alex
makelist(0,[]) :- !.
makelist(Dim, [[]|MoreList]) :- !, DimLeft is Dim - 1,
makelist(Dim,MoreList).
createarray([],[]).
createarray([Dim],[Array]) :- !, makelist(Dim,Array).
createarray([Dim|MoreDim], [Front|Array]) :- !, makelist(Dim,Front),
createarray(MoreDim,Array).
this would create an `empty' array comprised of `lists-of-lists' that can
represent the data.
for example, to create a 3 x 3 array, one would do.
createarray([3,3],X).
X = [ [ [], [], [] ] , [ [], [], [] ] ]
that could be used to put in numbers in random spots...
> Yes
> ?-
that's what access/4 was supposed to accomplish.
e.g.
suppose F=f(f(_,_,_),f(_,_,_),f(_,_,_)), then
access(1,3,F,27) will bind F to:
F=f(f(_,_,27),f(_,_,_),f(_,_,_))
etc.
but, reading an introductory book on Prolog might be the best way
to proceed. In the old days, there used to be buildings (called
`libraries') where you could read books (almost) for free...
Gj
Yes it is.
At least, I can do it for a 3 * 3 array.
I show you how below.
Its not obvious, but its easy when you know how.
>
> I can see how I could use recursion to do the for loops
> but once i go to pop in the number I'm stuck.
>
No, don't use recursion, far too complicated.
Use "fail" instead of using recursion.
If you have a magic square three columns wide,
lets use variables "A1, A2, A3, B1, B2, B3, C1, C2, C3"
for the 9 positions.
Like this :-
number( 0 ).
number( 1 ).
number( 2 ).
number( 3 ).
number( 4 ).
number( 5 ).
number( 6 ).
number( 7 ).
... etc. ...
number( 15 ).
find_all_possible_numbers :-
number( A1 ),
number( A2 ),
number( A3 ),
number( B1 ),
number( B2 ),
number( B3 ),
number( C1 ),
number( C2 ),
number( C3 ),
% Now write the numbers.
nl,
write( A1, ' ', A2, ' ', A3 ),
write( B1, ' ', B2, ' ', B3 ),
write( C1, ' ', C2, ' ', C3 ),
% Now go on to find the next set of numbers.
fail.
% Now write "Finished."
find_all_possible_numbers :-
n,
write( 'Finished.' ).
/*
Now you need to write a similar program,
but exclude most combinations of numbers,
so only valid magic squares are printed.
Something like this :
*/
program :-
number( A1 ),
number( A2 ),
number( A3 ),
number( B1 ),
number( B2 ),
number( B3 ),
number( C1 ),
number( C2 ),
number( C3 ),
% Add up the numbers.
Row_A_total is A1 + A2 + A3,
Row_B_total is B1 + B2 + B3,
Row_C_total is C1 + C2 + C3,
% Fail if the totals are not equal.
Row_A_total == Row_B_total,
Row_A_total == Row_C_total,
% Now write the numbers.
nl,
write( A1, ' ', A2, ' ', A3 ),
write( B1, ' ', B2, ' ', B3 ),
write( C1, ' ', C2, ' ', C3 ),
% Now go on to find the next set of numbers.
fail.
program :-
n,
write( 'Finished.' ).
/* You also need to allow for column totals,
to make sure they are all identical too.
So put this code in the program too :
Column_1_total is A1 + B1 + C1,
Column_2_total is A2 + B2 + C2,
Column_3_total is A3 + B3 + C3,
Column_1_total == Row_A_total,
Column_2_total == Row_A_total,
Column_3_total == Row_A_total,
Then do the diagonals in a similar way.
Diagonal_1 is A1 + B2 + C3,
Diagonal_2 is A3 + B2 + C1,
Diagonal_1 == Row_A_total,
Diagonal_2 == Row_B_total,
*/
/*
This is quite simple.
But I really don't know how to make a version
to find magic squares of any size.
I'd need to write a different program for each size of square.
*/
By the way, you can't learn Prolog from the web!
I strongly recommend this book as your first book on Prolog :
"Prolog Programming for Artificcial Intelligence" by Ivan Bratko,
published by Addison-Wesley, in paperback.
Martin Sondergaard,
London.
Hardly. You are merely trying to apply one known algorithm (of many) to compute
a solution for magic squares of odd orders. What is interesting with this
mathematical curiosity is finding the number of solutions, excluding mirroring
and turning, for a given order. We know that there is1 solution for a MS of the
3rd order and 880 for the 4th order. For a MS of the 5th order there are thought
to be in excess of 13 million solutions.
> So simple (in C,Java,etc,etc) but yet
> so hard (in PROLOG)
Not necessarily so (see below).
[snipped]
> The code below (in C) will create these magic squares
> of the odd numbers.
>
> void odd_num(int n) {
> int i,j,num=1;
> int nn=n*3/2;
> for(i=0; i < n; i++)
> for(j=0; j < n; j++)
> m[(j-i+nn)%n][(i*2-j+n)%n]=num++;
> }
You can apply a for-next loop in Prolog too. Let's mimic your C code (keeping a
0-based indexing scheme):
odd_num(N):-
N1 = N - 1,
NN = N * 3 // 2,
for(0,N1,I), % row
for(0,N1,J), % column
I1 is (J - I + NN) mod N, % row offset
J1 is (I * 2 -J + N) mod N, % column offset
Num is I * N + J + 1, % offset cell's value
assert(cell(I1,J1,Num)),
next(J,N1),
next(I,N1).
odd_num(_).
for(N,_,N).
for(Start,Stop,NumOut):-
Start1 is Start + 1,
Start1 =< Stop,
for(Start1,Stop,NumOut).
next(X,X).
> Well basically my question is, in Prolog, how is it
> (or it is) possible to have an two demensional array
> m[int][int] and then be able to input numbers into this
> array? i.e in "random" spots
>
> From my prolog experience I dont think this is possible
> is it?
Of course it is. Although Prolog doesn't have arrays, we can mimic them in a
number of ways:
1. Single elements: cell(Row,Col,Value)
2. Row elements: row(Row,ColumnValues)
3. Whole array: array(Cells)
and variations of these. Which one of these you choose to use will primarily
depend upon how values are to be accessed. Single elements are interesting when
you often need to access single cells, row elements and the whole array when you
often operate on groups of cells.
BTW, there's nothing "random" about calculating an offset.
[snipped]
To display your array you would implement something like this:
print_array(N):-
N1 = N - 1,
for(0,N1,I), % row
nl,
for(0,N1,J), % column
retract(cell(I,J,V)),
justify(V,Spaces),
write(Spaces), write(V), write(' '),
next(J,N1),
next(I,N1).
print_array(_):-
nl, nl.
justify(N,' '):- N < 10, !.
justify(N, ' '):- N < 100, !.
justify(N, ' '):- N < 1000, !.
justify(_, '').
To tie it all together:
magic_square(N):-
(0 is N mod 2
-> fail
; odd_num(N),
print_array(N)
).
And, finally, to run a query:
| ?- magic_square(11).
Well, that's a solution for magic squares of odd orders out of the way. It
becomes slightly more interesting with even orders.
Daniel
The sum of a row, column and main diagonal must be:
(N^3 + N) / 2
where N is the magic square's order and ^ is "to the power of".
[snipped]
> By the way, you can't learn Prolog from the web!
> I strongly recommend this book as your first book on Prolog :
> "Prolog Programming for Artificcial Intelligence" by Ivan Bratko,
> published by Addison-Wesley, in paperback.
Very good advice and an excellent choice of book (ISBN 0-201-41606-9).
Daniel
> So simple (in C,Java,etc,etc) but yet so hard (in PROLOG).
I don't agree.
> Magic Squares. For those that dont know what one is well here is a
> definition I grabbed off the net:
> "A magic square is an arrangement of the numbers from
> 1 to n^2 (n-squared) in an nxn matrix, with each number
> occurring exactly once, and such that the sum of the
> entries of any row, any column, or any main diagonal is
> the same. It is not hard to show that this
> sum must be n(n^2+1)/2."
This can easily be expressed in clp(FD), ie. a extension availible for
various Prolog-systems that allows you to work with
"constraints over a finite-domain".
In the following I will give a translation of the definition above for
magic-squares of size 3. This code can easily be extended to an
arbitrary problem-size.
magicsquare3(Mss) :-
magicsquare3_(Mss, Zs),
labeling([ffc], Zs).
magicsquare3_([[M11,M12,M13],[M21,M22,M23],[M31,M32,M33]], Zs) :-
Zs = [M11,M12,M13,M21,M22,M23,M31,M32,M33],
domain(Zs, 1, 9),
all_different(Zs),
M11+M12+M13 #= Sum, % rows
M21+M22+M23 #= Sum,
M31+M32+M33 #= Sum,
M11+M21+M31 #= Sum, % columns
M12+M22+M32 #= Sum,
M13+M23+M33 #= Sum,
M11+M22+M33 #= Sum, % diagonals
M31+M22+M13 #= Sum,
Sum #= 15.
> [code omitted]
This will construct ONE solution for the problem, given a problem-size N.
Using Prolog (and clpfd) you can not only generate one solution, but also:
. check if some given square is a magic square.
. work with partial instatiation (some parts of the square are
already known, others are still unknown).
. "create" all solutions to the problem.
If you want to do the same in C, you would have to implement some
algorithm for constraint-satisfaction search (+ backtracking).
Conclusion:
. Think about the various relations that can be identified.
Think of WHAT you want to express.
Do not think of HOW this should be executed by the computer.
(Remember: Prolog is a declarative language, not an imperative one)
. Do NOT try to translate a program from C or another imperative
language. This will almost always be a waste of time.
. Do NOT use: fail, assert, retract, write, format, !, functor, arg.
This list is -- of course -- incomplete...
Some of these "predicates" require profund knowledge of
prolog-internals. Others indicate a poor programming-style.
ciao,
Stefan
On a general level I agree, although IMHO it's a disservice to newcomers to
blindly preach this gospel. To reiterate a statement from one of my recent
postings, a good craftsman maintains and uses the right tools for the work in
hand. I venture to suggest this is one of those cases where use of
failure-driven loops and the internal database can be justified. It provides for
short and highly readable code and it is relatively efficient, although there
are a couple of places that warrant minor improvements. It's also very fast - a
magical square of 21st order is displayed IMMEDIATELY, despite 441 asserts and
retracts (and the handicap of running on the Windows' platform).
> So I'd suggest using recursion, and using functor/3 and arg/3 to access
> the array. Note that in the code that follows, I've kept the variable
> names the same as in the original example, to make it easier to see
> the correspondence. But I would suggest that using more meaningful
> names (e.g. `Array' rather than `M') would make this code easier to
> understand.
>
> % mode odd_num(in, out) is det.
> odd_num(N, M) :-
> make_array(N, M),
> NN is N * 3 // 2,
> odd_num_1(N, NN, 0, 1, M).
>
> % recursive loop over I
> % mode odd_num_1(in, in, in, in, partial -> ground) is det.
> odd_num_1(N, NN, I, Num0, M) :-
> ( I = N ->
> true
> ;
> odd_num_2(N, NN, I, 0, Num0, Num1, M),
> I1 is I + 1,
> odd_num_1(N, NN, I1, Num1, M)
> ).
>
> % recursive loop over J
> % mode odd_num_2(in, in, in, in, in, out, partial -> ground) is det.
> odd_num_2(N, NN, I, J, Num0, Num, M) :-
> ( J = N ->
> Num = Num0
> ;
> X is (J - I + NN) mod N + 1,
> Y is (I * 2 - J + N) mod N + 1,
> arg(X, M, Vector),
> arg(Y, Vector, Num0),
> Num1 is Num0 + 1,
> J1 is J + 1,
> odd_num_2(N, NN, I, J1, Num1, Num, M)
> ).
>
> % make_array(N, Array) creates an 2-dimensional NxN array,
> % whose elements are unbound variables.
> % mode make_array(in, out(partial)) is det.
> make_array(N, Array) :-
> functor(Array, array, N),
> make_array_args(1, N, Array).
>
> % mode make_array_args(in, in, partial -> partial) is det.
> make_array_args(I, N, Array) :-
> ( I > N ->
> true
> ;
> arg(I, Array, Row),
> functor(Row, row, N),
> I1 is I + 1,
> make_array_args(I1, N, Array)
> ).
>
> Note that I documented the mode and determinism of each procedure
> (using Mercury-style mode declarations, as it happens).
> For production code I would recommend also documenting the data
> representation and the types of each predicate's arguments.
Unfortunately, you have not written a complete program, which would serve as a
comparison. We can, however, note a considerable increase in code volume and
complexity. I therefore have my doubts that a newcomer would benefit from being
served such code; indeed, IMO it's much more likely to scare newcomers away from
Prolog. (Did I hear a "hurra" from the Mozart/Oz camp?)
> >> Well basically my question is, in Prolog, how is it
> >> (or it is) possible to have an two demensional array
> >> m[int][int] and then be able to input numbers into this
> >> array? i.e in "random" spots
> >>
> >> From my prolog experience I dont think this is possible
> >> is it?
>
> Yes, you can do this using functor/3 and arg/3, see the code above.
> Note that this only works for cases where you only need write-once,
> but that is indeed all you need for this example.
>
> >BTW, there's nothing "random" about calculating an offset.
>
> I think Alex McAskill means "random" in the sense of
> "random access" as opposed to "sequential access".
Mmmm...
[snipped]
> >To display your array you would implement something like this:
[snipped]
> The side-effect there is a rather nasty -- what happens if you
> want to display the array twice?
Again, on a general level I agree with you but doubt very much that this is
applicable here. Anyway, there is nothing to stop you retracting the facts
elsewhere, f.ex. on termination of the program, should you so prefer.
Daniel
> On a general level I agree, although IMHO it's a disservice to
> newcomers to blindly preach this gospel.
No. IMO, newcomers should be taught the "core parts" of prolog
programming (Recursion, universal termination, declarative
reading of programs, program-development methodology, ...). After
some time they can be confronted with the procedural aspects of
Prolog. (existential termination, procedural reading of programs,
chronological backtracking).
> To reiterate a statement from one of my recent postings, a good
> craftsman maintains and uses the right tools for the work in hand.
If you do not need to save information over backtracking, using
"assert/retract" is NOT the right tool. (use a data-structure instead)
> I venture to suggest this is one of those cases where
> use of failure-driven loops and the internal database can be
> justified. It provides for short and highly readable code [...]
Code that is purely based on side-effects is a nightmare to debug.
Some code that uses imperative language-features has no declarative
reading; it can only be read procedurally.
> and it is relatively efficient ...
I believe you. But this is not a matter of efficiency (since this
algorithm is in P anyway) ...
> Again, on a general level I agree with you but doubt very much that
> this is applicable here. Anyway, there is nothing to stop you
> retracting the facts elsewhere, f.ex. on termination of the program,
> should you so prefer.
"cleanup" is another issue when using "assert/retract". How should
one handle code that uses both exceptions AND "assert/retract"?
ciao,
Stefan
Oh no, not another person with blinkers/blinders? A person with previous
programming experience in an imperative programming language will quickly find
him/herself "at home" by first reviewing the procedural aspects of the Prolog
language. When this is combined with alternative examples of declarative
programming the advantages of programming "the Prolog way" become transparent.
The result is increased motivation for continued learning.
> > To reiterate a statement from one of my recent postings, a good
> > craftsman maintains and uses the right tools for the work in hand.
> If you do not need to save information over backtracking, using
> "assert/retract" is NOT the right tool. (use a data-structure instead)
In this case we did need to save information over backtracking (having chosen to
implement failure-driven for-next loops).
> > I venture to suggest this is one of those cases where
> > use of failure-driven loops and the internal database can be
> > justified. It provides for short and highly readable code [...]
> Code that is purely based on side-effects is a nightmare to debug.
Agreed, but hardly applicable in this case.
> Some code that uses imperative language-features has no declarative
> reading; it can only be read procedurally.
Is that so bad? Just because one is programming in Prolog doesn't mean that one
shouldn't program procedurally where this may be seen to be appropriate.
Honestly, I don't know whether to laugh or cry at such "tunnel"' ways of
thinking.
> > and it is relatively efficient ...
> I believe you. But this is not a matter of efficiency (since this
> algorithm is in P anyway) ...
So what?
> > Again, on a general level I agree with you but doubt very much that
> > this is applicable here. Anyway, there is nothing to stop you
> > retracting the facts elsewhere, f.ex. on termination of the program,
> > should you so prefer.
> "cleanup" is another issue when using "assert/retract". How should
> one handle code that uses both exceptions AND "assert/retract"?
Again, hardly applicable in this case. The internal database is merely being
used as a temporary container for "global variables". In the case where the
generated data is to be subsequently used there are many options available. One
could, f.ex., collect and store the data in a balanced binary tree (to
facilitate fast random access), and then program "the Prolog way".
Perhaps it's time to throw your blinkers/blinders away?
Daniel
|> Oh no, not another person with blinkers/blinders? A person with previous
|> programming experience in an imperative programming language will quickly find
|> him/herself "at home" by first reviewing the procedural aspects of the Prolog
|> language.
Let me try to see whether I understand this by putting it in a different context ...
A person with previous programming experience in assembly language programming, when
introduced to Pascal, will quickly find him/herself "at home" by first reviewing the
Pascal "goto" statement.
Yeah, sounds very reasonable to me.
Of course, you'll have to spend a lifetime later to explain that goto is considered harmful ...
And when a Brittish person starts to drive in Belgium, why not let him drive on the left
side for a while, so that he feels "at home" at first. Maybe he should also wear
blinkers/blinders at the beginning - just a matter of ignoring better what's going on in the
rest of the world.
Oh, and while we are at it, the preferred way to teach parachute jumping to a benjee jumper,
is of course to tie the parachute to his feet - this way is much more familiar to him !
Cheers
Bart Demoen
> Oh no, not another person with blinkers/blinders?
Learning a programming language (and a new paradigma) is just like
learning to play guitar. An error made in the early stages of the
learning process can hardly be corrected (or only with huge efforts)
in the later stages.
It is thus evident that the "core parts" MUST be taught/learned first.
You certainly agree with me that the imperative parts are not a
part of the "core" of prolog.
> A person with previous programming experience in an imperative
> programming language will quickly find him/herself "at home" by
> first reviewing the procedural aspects of the Prolog language.
People SHOULD not feel "too much at home" until they have really
understood the very basics.
> [Procedural aspects] Is that so bad?
No, it is not. But it is only a crutch, not more.
Remember that Prolog was intended to be a way of "programming in logic".
> Just because one is programming in Prolog doesn't mean that one
> shouldn't program procedurally where this may be seen to be appropriate.
Estimating that requires a person to understand the basics.
> Honestly, I don't know whether to laugh or cry at such "tunnel"' ways ...
If I were you, I'd rather laugh than cry...
>> > and it is relatively efficient ...
>> I believe you. But this is not a matter of efficiency ...
> So what?
So "Speed" and "Optimization" is irrelevant.
>> "cleanup" is another issue when using "assert/retract". How should
>> one handle code that uses both exceptions AND "assert/retract"?
> Again, hardly applicable in this case.
My statement did not refer to this concrete problem.
> The internal database is merely being used as a temporary container
> for "global variables".
Even in an imperative language the use of global variables should be
avoided whenever possible.
> Perhaps it's time to throw your blinkers/blinders away?
You call it blinders. I call it "focussing on the problem".
And -- IMHO -- that is what Prolog is all about.
ciao,
Stefan
It sometimes helps in the understanding process to read the whole contents,
Bart. Then you might not be so grossly off-context. I do appreciate your sense
of humour, though. :-)
Daniel
|> It sometimes helps in the understanding process to read the whole contents,
|> Bart. Then you might not be so grossly off-context.
It sometimes helps to think seriously about the thoughts of other people,
concerning how Prolog is used, shown and explained best, before starting
to talk about blinkers/blinders.
Lesson number one: do not underestimate others.
Bart Demoen
Yes, it would be an uncomplicated world if those with blinkers/blinders learnt
that lesson. ;-)
Daniel
Alex
>> By the way, you can't learn Prolog from the web!
>> I strongly recommend this book as your first book on Prolog :
>> "Prolog Programming for Artificcial Intelligence" by Ivan Bratko,
>> published by Addison-Wesley, in paperback.
>I strongly disagree. If you take that book as a starting point you'll
>end up writing very bad code indeed. Is that horrible definition of
>max/3 (or was it min/3) still in it?
Its in the second edition; I'm not sure if there is a third edition yet.
"The Art of Prolog" is a much better Prolog book IMHO. Bratko's book is
a readable introduction to both AI and Prolog but the Prolog code is
pretty poor.
lee
>Daniel Dudley <dud...@online.no> wrote:
>> Stefan Kral <e962...@stud3.tuwien.ac.at> wrote in message
>>> No. IMO, newcomers should be taught the "core parts" of prolog.
>>> [...] After some time they can be confronted with procedural aspects...
>> Oh no, not another person with blinkers/blinders?
>Learning a programming language (and a new paradigma) is just like
>learning to play guitar. An error made in the early stages of the
>learning process can hardly be corrected (or only with huge efforts)
>in the later stages.
>It is thus evident that the "core parts" MUST be taught/learned first.
>You certainly agree with me that the imperative parts are not a
>part of the "core" of prolog.
I certainly disagree! Prolog is a *programming language* after all.
The procedural semantics is therefore a core part of the language.
The "imperative parts" of Prolog include pretty much the whole language,
with some exceptions like the details of which (incorrect) unification
procedure is used. Certainly ":-" and "," (conjunction) have a
imperative meaning which is at least as well-defined as the declarative
meaning. Perhaps you are making the mistake of assuming that imperative
code cannot have a declarative meaning (look up my archived posting with
"inferential" in the title). I would say that the core idea of LP is
that code *can* have both imperative and declarative meanings.
I have to agree with Daniel in part at least - when I teach Prolog I
tell students how to implement a while loop in Prolog. However, I
*don't* tell them how to do it with assert etc (I don't even tell them
about assert, until much later perhaps), so I certainly don't advocate
Daniel's style of coding. The way you do a while loop in Prolog is with
a tail-recursive procedure. Its helpful to tell students how to code
such things so they can bridge the significant gap between understanding
code written by someone else and being able to write their own code.
I also tell them about the declarative meaning first - I talk about
while loops in the second or third lecture typically and I consider that
the students are still "newcomers" at that stage.
lee
> Its in the second edition; I'm not sure if there is a third edition yet.
> "The Art of Prolog" is a much better Prolog book IMHO. Bratko's book is
> a readable introduction to both AI and Prolog but the Prolog code is
> pretty poor.
When I taught Prolog, one of the exercises I used to set was the
minimum spanning tree problem. It used to amuse me when students
would copy and hand in as "their" solution Bratko's complex and
inefficient code, when a better solution can be constructed in a few
lines from a simple description of Prim's algorithm (which they were
given).
Matthew Huntbach
> ... The way you do a while loop in Prolog is with
> a tail-recursive procedure.
Whoa! don't you mean:
"The way you do a while loop in Prolog-based LP ..."
or
"The way you do a while loop in LP-idiom Prolog ..."
[assorted relevant personal opinions follow...]
The distinction between Prolog and LP is surely crucial in a newsgroup
which uneasily hosts discussion of both topics?
Prolog is a programming language, or virtual machine, defined by its
procedural semantics. It carries historical baggage, is debatably
rather ugly, but it is usefully well implemented (which is why it has
a comp.lang newsgroup: if it were just an abstract idea, it wouldn't
sustain - or deserve - discussion :-)
LP is a programming discipline/style/regime with some hard-to-resist
properties (I resist trying to enumerate them)
Realising LP in Prolog is a black art, requiring a decent understanding
of Prolog's non-declarative aspects. We don't achieve well-behaved
reusable code having clean declarative semantics just by avoiding
assert.
Regardless of the merits of the LP idiom, it is legitimate to discuss
non-LP Prolog idioms in c.l.p
Daniel's response to Alex' challenge was well-crafted, original and
post-worthy c.l.p-wise.
Fergus' advocacy of a recursive alternative was succinct and
rationalised
("do this instead and you get these properties") but his dismissive
"FORTRAN" jibe was provocative, and after that the thread degenerated
into
* assertions which, from an engineering perspective, can really only
be classified as religious beliefs
* unseemly squabbling over the souls of novices (or arrogant "we don't
discuss such things in front of the children" meta-discussions :-/
My interest in Prolog and the LP idiom is entirely pragmatic: when it
can
be made to work, it is a better basis for software reuse than anything
else
I've found, and I can realise ideas more quickly when the complexity of
my
code doesn't explode as I combine existing fragments in new ways.
c.l.p is an engineering newsgroup; Prolog is a machine; LP is an idiom;
realising LP in Prolog is difficult but worthwhile; unrationalised
assertions that LP is the One True Way are worse than a waste of
bandwidth when they sidetrack fertile threads; it is not heresy to
exploit LP for its remarkable software engineering advantages; I'm
an LP agnostic but I like my GUIs to be declarative...
Paul Singleton
>Lee Naish wrote:
>> ... The way you do a while loop in Prolog is with
>> a tail-recursive procedure.
>Whoa! don't you mean:
> "The way you do a while loop in Prolog-based LP ..."
>or
> "The way you do a while loop in LP-idiom Prolog ..."
I meant what I said. It was meant in the same sense as "the way you
do a while loop in Pascal is with a while statement (and the way you *do
not* do a while statement is with a goto). It had an imperative meaning
(to implemenent a while loop, use a tail-recursive procedure) as well as
a declarative meaning (while loops are implemented using tail-recursive
procedures). Polite English is riddled with the same dual meanings as
Prolog, the declarative-imperative (as above) and interrogative-imperative
(eg, "Excuse me, would you be so kind as to pass the cucumber sandwiches?").
Of course while loops can be implemented in different ways (assert,
goto, arithmetic if, etc). For the past 30 years or so the programming
language gurus have quite dogmatic about goto and I think the result is
good overall. What if they had said "goto is harmful for the structured
programming idiom, but of course this idiom is not the One True Way and
there are other perfectly valid idioms where goto is elegant, efficient
and the right tool for the job"? I suspect our graduates would still be
using goto on a regular basis.
lee
I'm confused. Are we talking about implementation of a while construct, i.e.
while a specified condition can be satisfied... (...do something), or the ...do
something part?
[snipped]
Daniel
|> I'm confused.
We know - no need to tell us ! Your previous postings were ample proofs.
Bart Demoen
You're now being pathetically childish. This forum is not the place to show it.
Daniel
Daniel
"Andrzej Szuksztul" <andrzej....@lido-tech.net> wrote in message
news:slrn8ca3jm.g3n.a...@gdndev30.lido-tech...