Sorry this is long, but I really have important things to show ...
I recently got my hands on Prolog. I really think I got the hang of
it: I can do anything I used to do in my (other) most favourite
languages, and often the Prolog version is even more concise, although
probably somewhat obscure to the non-informed. And to my surprise
(well, actually not really :-), I have come up with versions of common
predicates that apparently nobody conceived of before: here is my
version of the reverse predicate - I named it rev/2 because it could
otherwise clash with something in the library:
rev(List,_) :-
member(X,List),
asserta(was_in_list(X)),
fail.
rev(_,RevList) :-
findall(X,retract(was_in_list(X)),RevList).
I am extremely proud of the combination of using an aggregate
predicate and a database predicate in the last clause. But see later
for some damper on my hapiness.
I also have a brand new version of append - named app/3 for the same
reason:
app(L1,L2,_) :-
assert(result(L2)),
member(X,L1), asserta(was_in_list(X)),
fail.
app(_,_,_) :-
retract(was_in_list(X)),
retract(result(PartialRes)),
assert(result([X|PartialRes])),
fail.
app(_,_,L3) :-
retract(result(L3)).
I know it uses one more clause than the usual definition, but to be
frank, I think my version is much easier to understand: for one thing,
it avoids recursion (showing it is really unnecessary) and have you
noticed how I cunningly exploit the logical update view of dynamic
predicates in the second clause ? It is great that all things fit
together so nicely.
I actually like my version of append better than my version of
reverse, because I am inclined to the following implementation schema
(call it a design pattern if you want):
one (or more) clause puts the data in the database [where it
belongs naturally]
one (or more) clause does the actual work - all in the database
of course
one clause picks up the result from the database
app/3 does this beautifully - rev/2 probably needs some work to
achieve this ideal.
As you can tell, I am very taken in by Prolog, but I do have some
quibbles with Prolog as a language, its implementors and its
designers.
1) maybe you find my expercience too limited, but my versions of
rev and app show clearly that the sequence
member(X,L), asserta(foo(X))
is very useful: it is worth lifting this to the status of a
design pattern and have it abbreviated to something like
FORALL X IN L ASSERT foo(X)
What do people think about this ? [I am transferring stuff from my
other favourite languages - in particular COBOL - to Prolog here, but
this will help wider acceptance of Prolog, I am sure]
2) let's focus on my definition of rev for now (the app version
has the same issue): it works fine for lists of atoms, or integers,
mixed (atoms and integers) lists and even lists whose elements are any
term without variables (some textbooks name these terms ground, like
coffee :-); but when I reverse a list with terms with variables, then
these variables become disconnected; here is an example:
?- rev([X],[Y]), X == Y.
No
I have checkd this result in SWI, GNU, XSB, CIAO, ECLIPSE, SICStus and
B-Prolog: always the same No.
I then checked the ISO Prolog standard and it seems that this is
indeed what is required: assert/retract disconnect variables !
While this might help a logical reading of those builtins, I much
prefer a version of assert/retract that would keep the connection of
variables, so that my rev/2 (and app/3) work as intended
3) let's now focus on my app/3: somehow every Prolog implementation I
tried got the complexity of my predicate wrong; my code is cleary O(n)
with n the length of the first argument; but I have noticed that
Prolog systems make it into O(n*n) in practice; that's no good; no
wonder Prolog is hardly used - please Prolog implementors, do a favour
to your language and get this right !
4) both my rev/2 and app/3 exhibit an even stranger thing: they are
also linear in the size of the ELEMENTS of the involved lists;
everyone with half a brain just knows that append and reverse are by
nature independent of the size of the list elements - so why are
Prolog implementations getting this one wrong as well ? why is it too
difficult to get polymorphic types right for you ?
5) the following is really a bummer: I expect a predicate to be
callable at all times, even in the middle of some other complicated
code; what I mean is this - illustrating it on app/3 and rev/2: I will
call rev([1,2,3],RevL) in the middle of a call to app/3 by the
following code for append
app(L1,L2,_) :-
assert(result(L2)),
member(X,L1), asserta(was_in_list(X)),
fail.
app(_,_,_) :-
rev([1,2,3],RevL), write(RevL), nl,
retract(was_in_list(X)),
retract(result(PartialRes)),
assert(result([X|PartialRes])),
fail.
app(_,_,L3) :-
retract(result(L3)).
Now imagine the following call and answer (in SWI - but again
consistent in other Prolog systems):
?- app([a,b,c],[d,e],L).
[3, 2, 1, c, b, a]
L = [d, e]
Hard to believe, but there you go ! Apparently, the added call to
rev/2 operates in the same dynamic predicate space as the toplevel
call to app/3. For me this almost blew it. Luckily the fix is easy:
Prolog should encapsulate its asserts/retracts in a dynamicaly scoped
way. Shouldn't be too difficult for Prolog implementors to accomodate
for such a nice principle, I'd say.
6) The following made me really laugh: none of the predicates I wrote
(including rev/2 and app/3) work backwards, i.e. ?- app(X,Y,[1,2]).
does not split [1,2] in all possible pairs of lists making up [1,2].
Still, all Prolog textbooks cannot stop talking about this feature.
It seems that all this fuzz about bidirectional programming in Prolog
is just a myth. No big deal for me: I will not miss it. But why such
bad marketing ?
Before I go, I want to share with you my version of merge/3 (named
merg/2):
merg(L1,_,_) :- member(X,L1), assertz(list1(X)), fail.
merg(_,L2,_) :- member(X,L2), assertz(list2(X)), fail.
merg(_,_,_) :-
retract(list1(X)),
assertz(result(X)),
(retract(list2(Y)) ->
assertz(result(Y))
;
true
),
fail.
merg(_,_,_) :-
retract(list2(X)),
assertz(result(X)),
fail.
merg(_,_,L3) :-
findall(X,retract(result(X)),L3).
My design patterns work fantastic (apart from the problems reported
above), don't you think ?
I do have some more advice for the Prolog community, in particular
about the cut (!/0) whose scope I find rather limited, but maybe more
about that later: this was enough for one day's work. I am off now, to
refactor some more predicates. On my todo list are the inverse of
merg/3, and I would really like a version of member/2 which does not
come from the library. I have seen the library version of member/2 and
it is extremely recursive: it is both left and right
recursive. Probably Prolog programmers don't even know this, or else
they would avoid it as the plague: how can you be sure it works
correctly ? It must be based on an weird programming paradigm from
the seventies or maybe even the sixties. Anyway, if you feel you can
contribute, please do so in this newsgroup: together we can improve the
world, or at least Prolog !
My blessings,
http://groups.google.com/group/rec.food.drink.tea/msg/f5a636ed9ecb40db?dmode=source
That's an interesting thread.
I confess that I'm a naturally cranky person,
whose family finds it useful to regularly dose
me with coffee to mellow me out.
Perhaps tea might have a paradoxical effect?
regards, chip
>
> Are you a tea drinker? We know about their plot:
>
> http://groups.google.com/group/rec.food.drink.tea/msg/f5a636ed9ecb40db?dmode=source
I am a tea drinker (tea amongst other things actually), but could we
please stick to the issue ? My findings are way more interesting than
their plot.
My blessings,
> I recently got my hands on Prolog.
Welcome to the fray!
> rev(List,_) :-
> member(X,List),
> asserta(was_in_list(X)),
> fail.
> rev(_,RevList) :-
> findall(X,retract(was_in_list(X)),RevList).
>
> I am extremely proud of the combination of using an aggregate
> predicate and a database predicate in the last clause. But see later
> for some damper on my hapiness.
[snip]
Based on the following comments in your post, you
seem to mistrust recursion and feel that Prolog
would be better off without it. I don't think
I've encountered this point of view before...
As you experimented, you found that asserting
dynamic facts does not preserve the semantics
of variable identification in the same way as
their unification in rule chaining. That's a
keen observation on your part, and I look
forward to seeing if your opinion of recursion
(and polymorphism??) improves with practice.
> I do have some more advice for the Prolog community, in particular
> about the cut (!/0) whose scope I find rather limited, but maybe more
> about that later: this was enough for one day's work. I am off now, to
> refactor some more predicates. On my todo list are the inverse of
> merg/3, and I would really like a version of member/2 which does not
> come from the library. I have seen the library version of member/2 and
> it is extremely recursive: it is both left and right
> recursive. Probably Prolog programmers don't even know this, or else
> they would avoid it as the plague: how can you be sure it works
> correctly ? It must be based on an weird programming paradigm from
> the seventies or maybe even the sixties.
[snip]
There are generalizations to the cut construction
in various implementation dependent ways. One keyword
to search on is "getBackTrack" (resp. cutBackTrack),
which are useful in implementing Prolog within
Prolog, among other things.
I'm not sure what you mean by saying the standard version
of member/2 is "both left and right recursive." Here:
member(H,[H|_]).
member(X,[_|T]) :- member(X,T).
This is "tail recursive" in the sense that when
the outer instance of the member/2 goal invokes
the inner instance, it's the final subgoal and
there are no "open" backtrack points to consider.
So it can be implemented by the Prolog engine in
an efficient manner. What's not to like?
regards, chip
> Based on the following comments in your post, you
> seem to mistrust recursion and feel that Prolog
> would be better off without it. I don't think
> I've encountered this point of view before...
Are you condescending on purpose, or do you have no clue what I mean ?
> As you experimented, you found that asserting
> dynamic facts does not preserve the semantics
> of variable identification in the same way as
> their unification in rule chaining. That's a
> keen observation on your part, and I look
> forward to seeing if your opinion of recursion
> (and polymorphism??) improves with practice.
Same question. Or maybe you are just pulling my leg.
> There are generalizations to the cut construction
> in various implementation dependent ways. One keyword
> to search on is "getBackTrack" (resp. cutBackTrack),
> which are useful in implementing Prolog within
> Prolog, among other things.
Those are quite unimaginative and known in various implementations, e.g.,
in XSB they are named '_$savecp'/1 and '_$cutto'/1, and I could imagine
that any Prolog implementation must have those, even if they are not in
the manual. I was thinking about something more far reaching than that.
> I'm not sure what you mean by saying the standard version
> of member/2 is "both left and right recursive." Here:
>
> member(H,[H|_]).
> member(X,[_|T]) :- member(X,T).
>
> This is "tail recursive" in the sense that when
> the outer instance of the member/2 goal invokes
> the inner instance, it's the final subgoal and
> there are no "open" backtrack points to consider.
> So it can be implemented by the Prolog engine in
> an efficient manner. What's not to like?
It seems you do not know what I mean by left- and right-recursive.
Maybe I should rephrase that to head- and tail-recursive. What is an
"open" backtrack point ? Do there exist "closed" backtrack points as well
then ? You seem to be an expert in Prolog implementation: what can the
Prolog engine (PE ?) do so efficiently for tail-recursive calls it cannot
do for others ? I also find the terminology "inner and outer instance of a
goal" quite strange: no Prolog textbook I have read mentions it.
Now all the above is just chit-chat: can we focus on the real
contribution of my original post ? The database stuff, the design
patterns, the language design advice ? Please, I do not want to stall !
My blessings,
If I'd written what you wrote, this is how I'd want
someone to respond to me. I tried to respectfully
and accurately restate the main point, as it seems
to me, of your post. Possibly I failed in this,
but the point is to alert you quickly to potential
misunderstanding. As I said, I don't recall any
previous opinion that Prolog's reliance on recursion
was a weakness to be overcome. If I mistook your
point (aka "have no clue"), please enlighten me.
> > As you experimented, you found that asserting
> > dynamic facts does not preserve the semantics
> > of variable identification in the same way as
> > their unification in rule chaining. That's a
> > keen observation on your part, and I look
> > forward to seeing if your opinion of recursion
> > (and polymorphism??) improves with practice.
>
> Same question. Or maybe you are just pulling my leg.
I'm not pulling your leg. It seems to me you were
quite diligent to discover by testing (using varied
versions) that your implementation of reverse doesn't
preserve the ordinary semantics of unification.
To me your implementation is "swatting a fly with a
sledgehammer". Its dependence on non-local state
could be improved by retracting all was_in_list/1
facts at the outset, either in addition to or in
preference to the retraction at the end.
Here's the usual Prolog implementation of reverse/2
by "embedding" it in an auxiliary version reverse/3:
reverse(A,Z) :- reverse(A,[],Z).
reverse([],Z,Z).
reverse([H|T],X,Z) :- reverse(T,[H|X],Z).
This seems to me a more self-contained implementation.
Of course if yours could be shown to have a better
performance, then I'd be happy to grant that point.
> > There are generalizations to the cut construction
> > in various implementation dependent ways. One keyword
> > to search on is "getBackTrack" (resp. cutBackTrack),
> > which are useful in implementing Prolog within
> > Prolog, among other things.
>
> Those are quite unimaginative and known in various implementations, e.g.,
> in XSB they are named '_$savecp'/1 and '_$cutto'/1, and I could imagine
> that any Prolog implementation must have those, even if they are not in
> the manual. I was thinking about something more far reaching than that.
>
> > I'm not sure what you mean by saying the standard version
> > of member/2 is "both left and right recursive." Here:
>
> > member(H,[H|_]).
> > member(X,[_|T]) :- member(X,T).
>
> > This is "tail recursive" in the sense that when
> > the outer instance of the member/2 goal invokes
> > the inner instance, it's the final subgoal and
> > there are no "open" backtrack points to consider.
> > So it can be implemented by the Prolog engine in
> > an efficient manner. What's not to like?
>
> It seems you do not know what I mean by left- and right-recursive.
> Maybe I should rephrase that to head- and tail-recursive.
I don't know what head-recursive should mean. In the
present application, the clause which directly relates
to head H does not involve recursion (a predicate that
calls itself).
> What is an "open" backtrack point ?
> Do there exist "closed" backtrack points as well then ?
By backtrack point I mean a goal or subgoal for which
there are alternative ways of succeeding/satisfaction.
One may certainly have a case in which all but one of
the possibilities have been tried and failed, so that
only one possibility of success remains. In this way
what once may have been an "open" backtrack point (ie.
multiple alternatives to explore) can convert into a
"closed" backtrack point. I don't insist on this
terminology, though the distinction in states is
certainly important enough to deserve a definition.
Choice point is another phrase denoting places in
the rule chaining where alternatives still exist.
Deterministic is a word used to describe predicates
that succeed in at most one way, while nondeterministic
denotes predicates which might provide more than one
solution.
> You seem to be an expert in Prolog implementation: what can the
> Prolog engine (PE ?) do so efficiently for tail-recursive calls it cannot
> do for others ?
Loosely speaking there is an optimization for such tail-recursive
predicates as I've described that allows the implementation by
recursion to be reduced to an implementation by iteration/looping.
This saves stack space, which can be critical if the recursion goes
deep, and can boost the speed of computation.
> I also find the terminology "inner and outer instance of a
> goal" quite strange: no Prolog textbook I have read mentions it.
It fairly common across many languages to refer to the scope
of variables in a calling function/predicate as "outer" and
to the scope in a called function/predicate as "inner". For
recursion we have, at least indirectly, a function/predicate
that calls (invokes) itself. Feel free to suggest a better
vocabulary for drawing this distinction if inner/outer lacks
clarity.
> Now all the above is just chit-chat: can we focus on the real
> contribution of my original post ? The database stuff, the design
> patterns, the language design advice ? Please, I do not want to stall !
best wishes, chip
>Dear comp.lang.prolog,
>
>Sorry this is long, but I really have important things to show ...
>
>I recently got my hands on Prolog. I really think I got the hang of
>it: I can do anything I used to do in my (other) most favourite
>languages, and often the Prolog version is even more concise, although
>probably somewhat obscure to the non-informed. And to my surprise
>(well, actually not really :-), I have come up with versions of common
>predicates that apparently nobody conceived of before: here is my
>version of the reverse predicate - I named it rev/2 because it could
>otherwise clash with something in the library:
>
>rev(List,_) :-
> member(X,List),
> asserta(was_in_list(X)),
> fail.
>rev(_,RevList) :-
> findall(X,retract(was_in_list(X)),RevList).
>
Few threads above (thread name "append problem") there was
discussion regarding assert/retract. Although I don't agree with all
opinions expressed there, the following statement issued by Matthew
Huntbach seems to be written directly for you.
Quote:
"If you have to use asssert/retract to simulate mutable variables,
it indicates you really haven't started thinking in Prolog. I only
occasionally glance at this newsgroup, but over the years, many
times, I've seen Prolog newbies here struggling and jumping to using
assert/retract where there are much more elegant ways of doing what
they want to do which don't use them.
Pure logic and functional languages just don't use mutable
variables. In Prolog, assert/retract are rather ugly things mainly
used to get round the fact that otherwise no information is saved
over backtracking. There are specialist cases where the
self-modifying code they provide is useful - but this is not
something newbies should be concerned with, and it has no place in
an introductory tutorial.
Matthew Huntbach"
A.L.
Good jokes! With good advices wait unil you get rid of "newbie"
status.
See you 5 years from now.
A.L.
> Good jokes! With good advices wait unil you get rid of "newbie"
> status.
>
> See you 5 years from now.
>
> A.L.
It seems that the established Prolog masters are not happy with what I
wrote and propose. Maybe they could first tell me: have they ever seen
versions of append, reverse or merge that ressemble even remotely what
I wrote ? If not, can they judge them on their merit instead of on my
newbie status ? Probably too much to ask. Anyway, here comes my
proposal for a new cut device.
There are basically two ways to cut alternatives in Prolog: once/1 and
the cut (!/0) [I will treat if-then-else at some later occasion
perhaps - needless to say, there is something wrong there as well].
Both are limited in their scope: once(G) only cuts alternatives in G,
and the cut only EVERYTHING to the left. Lee Naish - a very enlightend
person indeed - once proposed a cutting predicate (whose name I
forgot) that would only take away the alteratives of the head: it
didn't make it into ISO (probably too far ahead of its time). The
predicates that implementations hide for users - like '_$savecp'/1 and
'_$cutto'/1 in XSB - are also quite limited: the scope is from the
save up to the cutto.
Here is what I want (actually badly need almost anytime I write a
larger piece of Prolog - something I am now doing on a regular basis).
I am illustrating it with an example, but I am using variables only
where they matter for showing my point:
p :- identify_goal(q,Id), r, foo(Id).
foo(Id) :- s , cut_goal(Id), ....
Two new builtin constructs are used: identify_scope/2 executes its
first argument (like call/1), and on success unifies its second
argument with an identifier of the goal. cut_goal/1 cuts all choices
left by the execution of the goal identified by its argument.
Note that the identifier can be passed around as any other Prolog
object.
Note that the choices for the intermediate goals (r,foo,s) are not
affected.
It should be clear that those two builtins can be used to implement
once/1, the cut, Lee Naish's head cut, the if-then-else and even the
if/3 (as in SICStus Prolog) - but the latter needs some inventivity
(anyone wants to try it ?).
If you would like to comment on these two new builtins, please do so,
whether on their usefulness, their operational semantics, how
difficult it would be to implement them.
With some hesitation - because I am not absolutely sure that this is
useful, but at least it is thinkable - I am also showing you another
quite innovative related predicate: uncut_goal/1. Again an example:
p :- identify_goal(q,Id), r, !, foo(Id).
foo(Id) :- s , uncut_goal(Id), ....
Note the differences: there is a cut after r, and foo/1 uses
uncut_goal. The idea is simple and intuitive: the cut has removed the
choices from q. Uncut_goal RE-INSTALLES these cut away choices !
I think this might turn out very powerfull as a programming aid: local
decisions to cut away choices, can be undone elsewhere. This shows a
similarity with undoing bindings to variables on backtracking, and I
must admit, I haven't worked out the analogy, but I anticipate a
duality here that might be best expressed in terms of categories. If
someone feels up to it: please go ahead.
My blessings,
>On Sat, 22 Sep 2007 10:49:27 -0500, A.L wrote:
>
>> Good jokes! With good advices wait unil you get rid of "newbie"
>> status.
>>
>> See you 5 years from now.
>>
>> A.L.
>
>It seems that the established Prolog masters are not happy with what I
>wrote and propose.
No.
>Maybe they could first tell me: have they ever seen
>versions of append, reverse or merge that ressemble even remotely what
>I wrote ?
Fortunately, no.
> If not, can they judge them on their merit instead of on my
>newbie status ? Probably too much to ask. Anyway, here comes my
>proposal for a new cut device.
>
Study, study, study! There will be never enough.
A.L.
Indeed, I think this poster well illustrates my point.
The solution proposed uses the clause database as a mutable list,
and implements loops over it using fail and findall. Well, yes, you
*can* do this, but the point is why? The only reason given by this poster
is to avoid recursion. Again, why? There are very simple and obvious
ways of solving this problem using recursion, there is no need to go
to the complexity and inefficiency of changing the clause database
and simulating loops using fail and findall to solve it.
So it looks to me as if this person, rather than embracing the clear
declarative way of solving problems, has instead used the crutch of
assert/retract to solve it in a way that is still thinking in terms
of loops over mutable variables. This person needs to be taught to get
over his or her fear of recursion and to be able to use it as a natural
tool in the programmer's toolkit. The whole point of logic programming
is that one can state a solution in terms of simple relationships,
but that does often involve recursion. If one isn't doing that, then
one is using Prolog, but not doing logic programming. In that case,
why use Prolog?
Matthew Huntbach
Its a bit odd that you appear to be one of the few that needs this :-)
Otherwise, it looks most like goto *var of gcc. Something that allows
you to write very unreadable code.
> I am illustrating it with an example, but I am using variables only
> where they matter for showing my point:
>
> p :- identify_goal(q,Id), r, foo(Id).
>
> foo(Id) :- s , cut_goal(Id), ....
> With some hesitation - because I am not absolutely sure that this is
> useful, but at least it is thinkable - I am also showing you another
> quite innovative related predicate: uncut_goal/1. Again an example:
>
> p :- identify_goal(q,Id), r, !, foo(Id).
>
> foo(Id) :- s , uncut_goal(Id), ....
You'll definitely make friends with the memory vendors. One of the
big reasons for having choicepoint pruning is to allow the system to
remove a lot of junk. If it needs to be able to get this junk back
from the wastebin it no longer can do this.
> My blessings,
>
> b...@rt.luna.be
Luna.be? ... :-)
Cheers --- Jan
I don't really disagree with the "general gist" of what you have to
say here, or elsewhere, and your points are well-taken. But to
nitpick a small thing, I have noticed you use the phrases "simple" and
"obvious" several times (in previous posts) to describe a potential
way to solve a problem (your way), vs. another way (the "newbie way,"
or "unprolog way"). I think it should occur to you that if it were as
"simple" and "obvious" as you say it is, all these newbies would be
doing it your way, don't you think? The point simply is, "simple" and
"obvious" are *OBVIOUSLY* relative terms, and you shouldn't use them
as if they aren't. You remind me of Kasparov wondering why the chess
novice can't see the "simple" and "obvious" mate in 15 that he so
easily sees. His ability to see it is what makes him an expert. Your
ability to see these Prolog things is what makes you (and Demoen and
Triska and Wielemaker, etc.) an expert.
It must also be said that Prolog in many cases forces one to do
extreme backflips in order to do something truly simple and obvious,
that would take one line of code in a more traditional language.
Reminds me of programming in a stack language and being forced to do
all manners of pops, dups, rolls, dips, etc. just to get access to the
value I need to manipulate (and then I have to do it all over again
for the next value to manipulate). The stack experts say "What's the
problem? The simple and obvious solution here is a 3-point roll-
reverse-dup-dip-swap maneuver, combined with a monadic pick-rotate-
pop!" And I'm like "Uh... in another lanugage I could simply write x=x
+1."
Regards.
>> There are very simple and obvious
>> ways of solving this problem using recursion...
> I don't really disagree with the "general gist" of what you have to
> say here, or elsewhere, and your points are well-taken. But to
> nitpick a small thing, I have noticed you use the phrases "simple" and
> "obvious" several times (in previous posts) to describe a potential
> way to solve a problem (your way), vs. another way (the "newbie way,"
> or "unprolog way"). I think it should occur to you that if it were as
> "simple" and "obvious" as you say it is, all these newbies would be
> doing it your way, don't you think? The point simply is, "simple" and
> "obvious" are *OBVIOUSLY* relative terms, and you shouldn't use them
> as if they aren't. You remind me of Kasparov wondering why the chess
> novice can't see the "simple" and "obvious" mate in 15 that he so
> easily sees. His ability to see it is what makes him an expert. Your
> ability to see these Prolog things is what makes you (and Demoen and
> Triska and Wielemaker, etc.) an expert.
I don't think the very basic use of recursion which is required to
write reverse or append in Prolog is equivalent to looking 15 moves ahead
in chess. To me, doing it this way is both simple and obvious because it
uses only the most basic core aspect of Prolog, it can be written in a
few lines, and ONCE ONE HAS GOT USED TO IT is so intuitive that one hardly
has to think about it.
The words in capitals are the key. I appreciate that, for some reason, these
techniques require a bit of getting used to. For some reason, many newbies
find recursion hard to use, and will go to great lengths using complex
side-aspects of the language, to avoid it. I am not fully sure why that is,
perhaps you and the orignator of the thread can say why.
Let us consider appending two lists, as one of the examples considered,
just about the most basic piece of recursion you can get in Prolog.
To append two lists, if the first is empty the result is the same as the
second.
Otherwise, to append two lists, if you append everything except the first
item of the first list to the second, then append the first item of the
first list to the result, you get the append of the two lists.
This is English, not Prolog, but it translates almost directly to the two
Prolog clauses of standard append. Now, you and the originaor of this thread
clearly do regard this as complex, to the point of likening it to a chess
grandmaster looking 15 moves ahead and seeking instead to use far more
complex programs which involve self-modifying code. Why?
Matthew Huntbach
>> There are very simple and obvious
>> ways of solving this problem using recursion...
>
>I don't really disagree with the "general gist" of what you have to
>say here, or elsewhere, and your points are well-taken. But to
>nitpick a small thing, I have noticed you use the phrases "simple" and
>"obvious" several times (in previous posts) to describe a potential
>way to solve a problem (your way), vs. another way (the "newbie way,"
>or "unprolog way"). I think it should occur to you that if it were as
>"simple" and "obvious" as you say it is, all these newbies would be
>doing it your way, don't you think? The point simply is, "simple" and
>"obvious" are *OBVIOUSLY* relative terms, and you shouldn't use them
>as if they aren't.
"I don't understand Relativity Theory and I don't know Relativity
Theory. But I am sure that Einstein was wrong. Therefore, I present
my own Theory of Everything, only 1 page long"..
Quote from sci.physics.
A.L.
But there are many more ways to describe append that do not translate
that well into Prolog. What about
To append two lists, create a new list, put all elements of the
first into the new list, then put all elements of the second
into the new list.
English that translates into Prolog is English that does not use
some notion of an imperative variable and splits list into the head
(an element) and tail (a list). With different but similar subsets of
the English language you can describe any program in any language in
English.
I'm convinced the tradional Prolog way of defining predicates that
transform datastructures is, once mastered, a powerful mechanism that
is less prone to errors than imperative alternatives. I doubt it is
more natural to the average person (whatever that may mean).
Cheers --- Jan
I'm not saying it is more natural. It's simple, in that it can be written
down very concisely in English and that translates directly to Prolog,
and it's obvious ONCE YOU GET USED TO THINKING THAT WAY. I think it plain,
however, from the way that many newbies struggle with it, that there is
a conceptual barrier which many people find difficult to cross. That is
why I think, when learning Prolog, it is important to do plenty of
exercises in the basic recursion and backtracking way to ensure thorough
familiarity with that, rather than be given the crutch of assert/retract
which enables people to escape into an imperative world. If you'd rather
be programming in an imperative way, then why use Prolog in the first
place?
This issue goes right back to the origins of Prolog, when it was genuinely
felt that it was so simple and natural that using it would make programming
so much easier. When this seemed not to be the case, the first Prolog
people wondered if the problem was that somehow their students' brains
had been damaged by doing imperative programming first, and thought that
maybe if they were taught Prolog first they would naturally think that way.
But even there, it does seem that somehow there are a small number of people
who find recursion simple and natural, and a large number who don't. I'm
still optimistic enough to think the barrier can be jumped with practice,
rather than to accept that most of humanity just can't and never will grasp it.
But if that really is the case, we might as well give up on Prolog.
Matthew Huntbach
Very few people will oppose this view. The power of Prolog is recursion,
logical variables and backtracking. Any course must teach these and
avoid as much as possible explaining there are ways to to imperative
programming in Prolog after all. Even with all tricks, Prolog is a lousy
imperative programming language!
> rather than to accept that most of humanity just can't and never will grasp it.
> But if that really is the case, we might as well give up on Prolog.
Not so soon. I know enough people that have fun and make a living
because they understand these mechanisms :-) I very much doubt there is
any hope Prolog (or more generally Logic Programming) will reach wide
acceptance ever though. Except for mathematicians, its just not natural
enough ...
Cheers --- Jan
I don't either, personally, but that wasn't the point. The point was,
"simple" and "obvious" are obviously relative terms. If they aren't
relative, then you seem to imply that newbies purposefully do the non-
simple and non-obvious even though they see the simple and obvious
solution staring them in the face.
>> If not, can they judge them on their merit instead of on my
>>newbie status ? Probably too much to ask. Anyway, here comes my
>>proposal for a new cut device.
>>
>
> Study, study, study! There will be never enough.
Study is best performed under the guidance of masters. But apparently,
the Prolog masters can only say "study" or "get used to it" - that's even
worse than Zen masters who at least have a deeper message in their
otherwise incomprehensible words - even if that message misses the point
as well.
Anyway, I am not yet giving up on you guys !
Why is recursion a bad thing ? Here is the answer: remember the old days
when things were better ? One of those better things was ... the absence
of recursion in languages like Fortran and Cobol. Most new Prolog
programmers these days are not old enough to remember that of course, but
the abhorrence from recursion is deeply grafted in our DNA: it is just
plain wrong to define a concept in terms of itself, this is clear to any
person in the street, whether programmer, matematician, welder or book
keeper. The only way to make sense of such self-defining definitions is
to rely on a meta-principle: induction. But induction does not
always apply: you must have a well-founded order to do it on, and you must
check that your recursive definition respects that order. That's why
textbooks give a definition of Ackerman's function and imediately ask you
to prove that this actually defines something. Now, it is clear that
proving anything at all, goes way beyond most programmer's skills. Still,
without proofs, all of your recursively defined predicates may just mean
gibberish !
On the other hand, even babies use iteration: cry until you get food. No
nonsense like "I cry and if I do not get food, I will call the same
procedure again".
But the focus of all this is wrong: my proposals for new builtins (or a
new semantics for old ones), my new design patterns for Prolog ... no
fundamental reaction to that. Just something from Mister SWI about memory
vendors - I might react to that in a later contribution.
I am sure of what will happen: the gurus will put me in their kill-file,
the other newbies with great ideas will be put off by the lack of
response to novelty in this news group and the Prolog masters will keep on
helping students out with their homework. I might just move on to another
newsgroup: that's not a threath, it is just a real possibility. But sad
for Prolog. And I find the reaction by A.L. (Einstein, relativity theory
...) all the more inappropriate, because also my PhD supervisor was
convinced that general relativity was too complicated to be correct.
So, please can someone with brains come to the real point ?
My blessings,
Funny you should ask. The solution you are referring to where I used
"self-modifying code" was actually an attempt to get *TO* the basic
Prolog ability of backtracking (something you say newbies should be
drilled on - and I agree). To me, the other solutions were more
exotic and fancy, and required much more knowledge of Prolog libraries
and built-in predicates. I was just trying to stick to ultra-basics.
I know you disagree, and think that what I did was non-obvious and
uber-complex, but I suppose that's what makes opinions what they are -
opinions.
I was simply trying to get to a point where I could do a simple
"fact1(X), fact2(Y), fact3(Z), fail" and have Prolog backtrack and
spit out all the solutions. In that, I was a success, and I call that
about as fervent of an attempt to get at the "basics" as you'll find.
Please - criticize my solution all you want. I beg you to. Just
understand that my attempt was actually to try to do "standard, ultra-
basic" Prolog. If I failed in that attempt, I suppose it's better to
have tried and failed than to not have tried at all.
Regards.
> On the other hand, even babies use iteration:
Huntchback, I think this guy actually has a good point. In peoples'
everyday lives, they don't think recursively, they think iteratively.
If some guy on the street asks me directions to go somewhere, I don't
give him a recursive set of directions. I give him an iterative set
of directions. When I work on a car engine, I don't look at a
recursive instruction manual, I look at an iterative manual. For just
about every single problem I can think of in daily life - even mowing
my lawn - I don't think about the problem recursively...
mowlawn_finished([]).
mowlawn-finshed([H|T] :- cutgrass(H), mowlawn_finished(T).
I think about it iteratively (and so does everyone else). I think
about it in terms of doing strips at a time, making quarter turns or
180 degree turns with the mower, checking to see if there is more
grass left to cut, etc. Basically a big while loop with a bunch of
instructions and checks in the middle of it.
Note that I am not putting down recursion, nor the need for a newbie
to learn recursion in Prolog. Nor am I advocating Prolog to
(necessarily) get away from recursion. I am merely answering your
previous question by saying I believe this guy makes a strong point
about it "being in the DNA." Nobody walks around thinking recursively
in their daily lives, in solving daily problems like changing the
baby's diaper or making food. At least, I don't know anyone who does.
Regards.
There will be NO reaction - for the same reeason why on sci.physics
there is no reaction to discoveries of perpetual motion.
>I am sure of what will happen: the gurus will put me in their kill-file,
>the other newbies with great ideas will be put off by the lack of
>response to novelty in this news group and the Prolog masters will keep on
>helping students out with their homework. I might just move on to another
>newsgroup: that's not a threath, it is just a real possibility.
Good! Please!
A.L.
When Prolog was first developed, the main argument for it was that as it
was based on a human mechanism, logic, rather than the electronics of
a computer as standard programming languages are, it should be much more
natural and easy to use than standard programming languages. So if it
isn't, what's the point?
Matthew Huntbach
> Why is recursion a bad thing ? Here is the answer: remember the old days
> when things were better ? One of those better things was ... the absence
> of recursion in languages like Fortran and Cobol. Most new Prolog
> programmers these days are not old enough to remember that of course,
In my case no, when I was first taught Prolog I found it fun and so
much more easy to use than the imperative languages of the day. I didn't
find recursion a barrier, it seemed to me to be a natural way of
expressing solutions to problems.
> but the abhorrence from recursion is deeply grafted in our DNA: it is just
> plain wrong to define a concept in terms of itself, this is clear to any
> person in the street, whether programmer, matematician, welder or book
> keeper. The only way to make sense of such self-defining definitions is
> to rely on a meta-principle: induction. But induction does not
> always apply: you must have a well-founded order to do it on, and you must
> check that your recursive definition respects that order. That's why
> textbooks give a definition of Ackerman's function and imediately ask you
> to prove that this actually defines something. Now, it is clear that
> proving anything at all, goes way beyond most programmer's skills. Still,
> without proofs, all of your recursively defined predicates may just mean
> gibberish !
If you insist, recursion can be described in terms of how it's
implemented underneath, which is iteratively putting things onto
and taking them off stacks. But being able to use recursion just
opens up problem solving techniques - to suggest it's just "plain wrong"
is mad - it;s used in all sorts of common software.
Look again at my recursive description of list appending:
"To append two lists, if the first is empty the result is the same as the
second. Otherwise, to append two lists, if you append everything except the
first item of the first list to the second, then append the first item of
the first list to the result, you get the append of the two lists."
Just what is wrong with that? Why do you suggest there is some natural
"abhorrence" of it that you recoil from it?
Or what about
"to sort a list if it has one or no elements it is sorted,
otherwise divide it into two lists, all those elements less than
the first, all those greater than the first, sort each list, append
the sorted lists together"
This is quick sort, if you will not use recursion, you will be stuck with
less efficient sorts. Can you point out exactly what is so abhorrent about
it that you would prefer to boycott it than try to understand it?
Matthew Huntbach
>> but
>> the abhorrence from recursion is deeply grafted in our DNA: it is just
>> plain wrong to define a concept in terms of itself....
>
>> On the other hand, even babies use iteration:
> Huntchback, I think this guy actually has a good point. In peoples'
> everyday lives, they don't think recursively, they think iteratively.
> If some guy on the street asks me directions to go somewhere,
If I want to go somewhere, and I don't know the way, I think of a place
in between where I am now, and that other place. Then either the journey
from that in between place to one of the other places is a straight
road, or I have to work out the journey from my starting point to the
mid-point, and work out the journey from th mid-point to where I want
to go. That's recursion.
> Note that I am not putting down recursion, nor the need for a newbie
> to learn recursion in Prolog. Nor am I advocating Prolog to
> (necessarily) get away from recursion. I am merely answering your
> previous question by saying I believe this guy makes a strong point
> about it "being in the DNA." Nobody walks around thinking recursively
> in their daily lives, in solving daily problems like changing the
> baby's diaper or making food. At least, I don't know anyone who does.
Suppose I'm climbing to the top of the building. I climb a set of steps,
turn round and either I'm at the top, or there's another set of steps
facing me. If there's another set of steps facing me, I've reduced the
number of sets of steps I have to climb by one, but I'm still faced
with a smaller version of the same problem - climbing a number of sets
of steps to the top of the building. That's recursion.
If I'm mowing the lawn, what do I do - I mow part of the lawn, then I've
reduced the problem to mowing the rest of the lawn, which I do in the
same way. That's recursion.
Now, I have to accept, because I've seen it so many times, and this guy
is a particularly pathological case, that many people do find recursion
hard to use, particularly when expressed using formal notation. But
I think one of the points about Prolog is that it's a language where
recursion is even more central than other languages, because it replaces
loops. That's why it can be a good teaching tool, because it *forces* people
to use recursion rather than seek escape routes from it. I don't think it
helps just to write it off as so difficulkt one won't even bother with it,
and instead will use all sorts of complicated mechanismss to get round it.
Matthew Huntbach
> Why is recursion a bad thing ? Here is the answer: remember the old days
> when things were better ? One of those better things was ... the absence
> of recursion in languages like Fortran and Cobol.
Actually the first time I heard the name of recursion was in the mid-70es when I
complained to the optional "informatics" teacher that I couldn't translate into
working Fortran the determinant computation method I had just learned in math class.
"Fortran isn't recursive" I was told. Later that year I wrote a "random
instantiator for formal grammars" that involved encoding (recursive) grammars as
Fortran statements, then having the functions invoked by the statements, rewrite
the unoptimized (and thus very regular) machine code around their calling
points, to turn said machine code into a graph representation of the grammar
that was finally handed to a small interpretor.
That time the mystified teachers exclaimed "but Fortran isn't recursive !??..."
> Most new Prolog
> programmers these days are not old enough to remember that of course, but
> the abhorrence from recursion is deeply grafted in our DNA:
Thank God for biodiversity :) And grammar :)
In good computer science tradition however I'm afraid nobody actually
performed the tests. Correct me if I'm wrong. In social science they
would take a lot of students, split them into two groups and run an
experiment. Thats not an easy experiment as it depends on how you
prepare the students, the problems and the metrics you define for a
good/better result. Still, if this experiment was carried out in
enough CS departments we could probably say something sensible about
this claim.
CS has developed a lot of languages, but basically no evaluation :-)
They are (almost) all equally expressive (= Turing complete). Some
might not be able to represent certain problems with optimal
complexity. Some programmers like logic, others iteration, some
like recursion, some don't, some like types, some don't, some like
objects (in many flavours) and some don't.
As we cannot compare languages the only remaining question is whether
you like the language or not. I happen to like Prolog :-) As long as
there are enough people like me, Prolog has a point. Its no different
than pizas, as long as there enough people that like them, making
Pizas makes sense.
B.t.w. it is totally irrelavant to this discussion what the original
developers had in mind.
Cheers --- Jan
Good question. The answer is, there doesn't necessarily need to be a
point. It's a language, just like any other. If there are people who
program in it and like it - great. If there aren't, there aren't.
It's as simple as that.
You're an alien :-)
> I don't think it
> helps just to write it off as so difficulkt one won't even bother with it,
> and instead will use all sorts of complicated mechanismss to get round it.
Agreed.
It seems to me that the basic issue in your writing is that you expect Prolog underneath model of computation to be different from what it is: the database alteration by means of retract and assert* is not intended to be particularly efficient, because the focus of Prolog approach is meant to be more on rules application than on facts alteration.
Modifying the knowledge base just to store temporary results is obviously possible, and as other threads would tell you, exactly one of the things that newbies, like you qualify yourself, tend to overuse.
I saw, long time before ISO, code similar to yours in many students code snippets; they were OK, but not as elegant as other solutions designed not to leave intermediate traces of their execution into the knowledge base they then had to remove right before completion (that many times were not fully cleaned too, defect that does not seem to affect your examples). This is to plainly say that your code looks correct, but neither particularly innovative, nor actually efficient.
The lack of efficiency in altering the knowledge base loose relevance when it can help implementing something like non-chronological backtracking, but that's a different story.
> 1) maybe you find my expercience too limited, but my versions of rev
> and app show clearly that the sequence member(X,L), asserta(foo(X))
> is very useful: it is worth lifting this to the status of a design
> pattern and have it abbreviated to something like FORALL X IN L
> ASSERT foo(X) What do people think about this ? [I am transferring
> stuff from my other favourite languages - in particular COBOL - to
> Prolog here, but this will help wider acceptance of Prolog, I am
> sure]
[Well, I'm afraid statements like your last sentence above are not preparing the right mood around your other text! :) Seriously: I know almost nothing about Object Oriented Cobol, but verbosity, rigidity of structure, and imperativeness of plain ol' COBOL have quite a little to share with Prolog, IMHO.]
I personally think that member(X,L), asserta(foo(X)) is already a quite compact way to express your need, not to urge for a more concise replacement.
> 2) let's focus on my definition of rev for now (the app version has
> the same issue): it works fine for lists of atoms, or integers, mixed
> (atoms and integers) lists and even lists whose elements are any term
> without variables (some textbooks name these terms ground, like
> coffee :-); but when I reverse a list with terms with variables, then
> these variables become disconnected; here is an example:
>
> ?- rev([X],[Y]), X == Y. No
>
> I have checkd this result in SWI, GNU, XSB, CIAO, ECLIPSE, SICStus
> and B-Prolog: always the same No.
Whether there was not a rev([a],[a])-like fact in your base, this is not surprise. It's a consequence of the closed world hypothesis, combined with the inability of Prolog to perform higher order logic reasoning, I would say.
> 3) let's now focus on my app/3: somehow every Prolog implementation I
> tried got the complexity of my predicate wrong; my code is cleary
> O(n) with n the length of the first argument; but I have noticed that
> Prolog systems make it into O(n*n) in practice; that's no good; no
> wonder Prolog is hardly used - please Prolog implementors, do a
> favour to your language and get this right !
Might I ask how you measured that?
> 4) both my rev/2 and app/3 exhibit an even stranger thing: they are
> also linear in the size of the ELEMENTS of the involved lists;
> everyone with half a brain just knows that append and reverse are by
> nature independent of the size of the list elements - so why are
> Prolog implementations getting this one wrong as well ? why is it too
> difficult to get polymorphic types right for you ?
Ditto.
> 5) ...Hard to believe, but there you go ! Apparently, the added call
> to rev/2 operates in the same dynamic predicate space as the toplevel
> call to app/3. For me this almost blew it. Luckily the fix is easy:
> Prolog should encapsulate its asserts/retracts in a dynamicaly scoped
> way. Shouldn't be too difficult for Prolog implementors to
> accomodate for such a nice principle, I'd say.
Here again, the fundamental idea of how the knowledge base is meant to be used is key.
> 6) The following made me really laugh: none of the predicates I wrote
> (including rev/2 and app/3) work backwards, i.e. ?- app(X,Y,[1,2]).
> does not split [1,2] in all possible pairs of lists making up [1,2].
> Still, all Prolog textbooks cannot stop talking about this feature.
>
> It seems that all this fuzz about bidirectional programming in Prolog
> is just a myth. No big deal for me: I will not miss it. But why such
> bad marketing ?
I'm afraid the books you read weren't clear enough on how unification works, or that their authors were cheating.
> I do have some more advice for the Prolog community, in particular
> about the cut (!/0) whose scope I find rather limited, but maybe more
> about that later: this was enough for one day's work. I am off now,
> to refactor some more predicates. On my todo list are the inverse of
> merg/3, and I would really like a version of member/2 which does not
> come from the library. I have seen the library version of member/2
> and it is extremely recursive: it is both left and right recursive.
> Probably Prolog programmers don't even know this, or else they would
> avoid it as the plague: how can you be sure it works correctly ? It
> must be based on an weird programming paradigm from the seventies or
> maybe even the sixties. Anyway, if you feel you can contribute,
> please do so in this newsgroup: together we can improve the world, or
> at least Prolog !
My understanding of right recursion and left recursion relates to grammar production rules and, indirectly, to parser classification, but that doesn't fit your statement. Might I ask you to elaborate further your conjecture on the "weird programming paradigm"?
Cheers,
Andrea.
>> 6) The following made me really laugh: none of the predicates I wrote
>> (including rev/2 and app/3) work backwards, i.e. ?- app(X,Y,[1,2]). does
>> not split [1,2] in all possible pairs of lists making up [1,2]. Still, all
>> Prolog textbooks cannot stop talking about this feature.
>>
>> It seems that all this fuzz about bidirectional programming in Prolog
>> is just a myth. No big deal for me: I will not miss it. But why such
>> bad marketing ?
> I'm afraid the books you read weren't clear enough on how unification works,
> or that their authors were cheating.
This is actually a good point - Prolog is often promoted on the grounds
that programs can be multi-moded, but in reality its operational model
means this is rarely so except for toy examples. Of course, if one insists
on a Prolog programming style which eschews Prolog's underlying logic
programming mechaniamss and instead concentrates on its extra-logical
features, one should be even less surprised to find it doesn't work as advertised.
I think this indicates, again, that a lot of what is said about Prolog now
actually goes back go the early optimistic years of logic programming,
and does not reflect the limited reality of Prolog as a practical language.
That is, there was a logic programming dream of writing statements in pure
logic and the machinery underneath would do all the computations and give you
answers and you wouldn't have to think about how it did it. Prolog was only
a first step towards this, as it wasn't really "magic" and actually was
strongly dependent on its underlying mechanism which anyone doing realistic
programming in it would need to be thoroughly familiar with. But people
confused and confuse now "Prolog" with the logic programming dream, and hence
expect Prolog to do what the dream said logic programming would eventually do.
Matthew Huntbach
>> When Prolog was first developed, the main argument for it was that as it
>> was based on a human mechanism, logic, rather than the electronics of
>> a computer as standard programming languages are, it should be much more
>> natural and easy to use than standard programming languages. So if it
>> isn't, what's the point?
> In good computer science tradition however I'm afraid nobody actually
> performed the tests. Correct me if I'm wrong. In social science they
> would take a lot of students, split them into two groups and run an
> experiment. Thats not an easy experiment as it depends on how you
> prepare the students, the problems and the metrics you define for a
> good/better result. Still, if this experiment was carried out in
> enough CS departments we could probably say something sensible about
> this claim.
There was some experimental work on this, I'm thinking particularly of
Richard Ennals' work on teaching logic programming in schools, which was
published in the 1982 Internatinal Conference on Logic Programming.
> CS has developed a lot of languages, but basically no evaluation :-)
> They are (almost) all equally expressive (= Turing complete). Some
> might not be able to represent certain problems with optimal
> complexity. Some programmers like logic, others iteration, some
> like recursion, some don't, some like types, some don't, some like
> objects (in many flavours) and some don't.
>
> As we cannot compare languages the only remaining question is whether
> you like the language or not. I happen to like Prolog :-) As long as
> there are enough people like me, Prolog has a point. Its no different
> than pizas, as long as there enough people that like them, making
> Pizas makes sense.
As we have seen from the comments of newbies here, Prolog continues to be
promoted on a manifesto which made sense in the early optimistic days of
logic programming, but has been disproved by practical experience.
That is people are led to believe Prolog is some sort of magic where you
don't have to think about what goes on operationally underneath, and are
then disappointed to find it doesn't work that way. Also, the claim that it
is natural and easy falls down because the natural easy style requires
recursion, and as we have seen this really does seem to be a stumbling
block to many people.
Prolog has had the advantage of being extensively promoted in academia,
though more so in Europe than the US. Very many students have been made to
go through learning Prolog. There was at least one university Computer
Science department which taught students to program in Prolog first before
any other language. To some extent Prolog has survived because there were
over-optimistic claims about it when it was first developed, it appealed
to academics, and it became a standard part of the university Computer
Science curriculum appearing there out of habit rather than because there
waas any real demonstration of its usefulness. If it were really useful,
wouldn't it be more widely used, given that the huge number of people
with Computer Science degrees who have gone through learning it, this
over a period of nearly three decades now?
I like Prolog, and I've written a book and papers on logic programming, so
I can hardly be accused of an irrational dislike or lack of knowledge of it.
However, as the continuing stream of puzzled enquiries from newbies in this
newsgroup indicates, it does seem there are a lot of people taking it up
for no good reason other than they have heard the old propaganda for it,
and then find it doesn't live up that propaganda. Also we are constantly
finding these newbies saying it is a very difficult language. If the language
is difficult, and people are not sure what it is for, and it is only
taken up because people have been misled about its capabilities, and few
people have ever really discovered domains where it is more suitable than
other languages, then just what is its point?
Matthew Huntbach
No, because:
a. Majority of programming is GUI development, and Prolog is not
strong in this area,
b. Majority of programming is simple data base front end. Prolog is
not strong in this area,
c. The rest of programming is graphics, number crunching and such.
Prolog is not strong in this area.
In addition, languages don't count that much any more. Important is
development environment (IDE) and associated libraries such as
libraries for web programming, XML, communication, middleware,
interfacing with other languages (what is pain in the butt). Prolog
has some libraries, but generally this stuff is 20 years behind the
current state of the art.
As for me, the REAL and substantial advantage of Prolog is
constraint programming. Doing constraint programming in C++/Java (I
have already tried) is like pushing square pegs through round holes.
Prolog provides natural environment for constraint programming
paradigm.
A.L.
>> waas any real demonstration of its usefulness. If it were really useful,
>> wouldn't it be more widely used, given that the huge number of people
>> with Computer Science degrees who have gone through learning it, this
>> over a period of nearly three decades now?
> No, because:
>
> a. Majority of programming is GUI development, and Prolog is not
> strong in this area,
> b. Majority of programming is simple data base front end. Prolog is
> not strong in this area,
> c. The rest of programming is graphics, number crunching and such.
> Prolog is not strong in this area.
Yes, Prolog is not strong in most of the areas which programming is
about.
> In addition, languages don't count that much any more. Important is
> development environment (IDE) and associated libraries such as
> libraries for web programming, XML, communication, middleware,
> interfacing with other languages (what is pain in the butt). Prolog
> has some libraries, but generally this stuff is 20 years behind the
> current state of the art.
Part of the problem, I think, is that Prolog doesn't fit well into
the object-oriented model fo programming. Prolog isn't about
separate components interacting, it's really about one big global search tree.
> As for me, the REAL and substantial advantage of Prolog is
> constraint programming. Doing constraint programming in C++/Java (I
> have already tried) is like pushing square pegs through round holes.
> Prolog provides natural environment for constraint programming
> paradigm.
Yes, part of the sales pitch for logic programming was that it could involve
some complex constraints stuff. As it is, the core of Prolog with its
simple search-with-backtracking and unification mechanism is a very crude
form of constraint. So if you are saying Prolog is good because it handles
constraint programming well, I don't think you're talking about the core of
Prolog, rather it's additional facilities added to some varieties of Prolog.
But could these equally well be added through appropriate libraries to, say Java?
Could you talk me through why not? After all, if it can be done that
way, you lose the problem of having to interface with other languages
to do the GUI and database front end and number crunching stuff, and you
say interfacing with other languages is a pain in the butt anyway. You also
lose all those newbies complaining about the language becayse it won't
behave in an imperative way.
Matthew Huntbach
Maybe Prolog is good, maybe Prolog is bad. It will stand or fall on
its own merits, fairly or unfairly. But should a language be
structured around newbie complaints, or lack thereof?
Not sure. There was heated discussion here some time ago with mixed
results. I am not sure that object orientation and prolog mix well,
but now I am developing oposite view... maybe I will write about my
experience when I collect more facts.
>> As for me, the REAL and substantial advantage of Prolog is
>> constraint programming. Doing constraint programming in C++/Java (I
>> have already tried) is like pushing square pegs through round holes.
>> Prolog provides natural environment for constraint programming
>> paradigm.
>
>Yes, part of the sales pitch for logic programming was that it could involve
>some complex constraints stuff. As it is, the core of Prolog with its
>simple search-with-backtracking and unification mechanism is a very crude
>form of constraint. So if you are saying Prolog is good because it handles
>constraint programming well, I don't think you're talking about the core of
>Prolog, rather it's additional facilities added to some varieties of Prolog.
>But could these equally well be added through appropriate libraries to, say Java?
>Could you talk me through why not?
Well... CLP(FD) is pretty well integrated with Prolog; see SICStus
or ECLIPSE. It is hard to say that CLP is "add on".
However, the most important issue: constraint programming is
declarative. Of course, you can SIMULATE declaraivenes in Java or
whatever, but it will be just simulation. Prolog has all what is
needed. Declarativenes in optimization and constraint solving was
recognized long ago in Operations Research. Languages for defining
optimization problems are declarative; see AMPL, OPL, MOSEL, MPL and
such. From my own experience: I prototyped some optimization problem
in MOSEL. This required about 150 lines of MOSEL. However, for
various (technical and business) reasons I had to re-write this
model in Java using the library provided by the same vendor that
provides MOSEL. It was well over 2000 lines.
I am just completing the project that has 15K lines of Prolog. I am
not even trying to think how long it would take to do this in Java
(Prolog took about 1000 hours) and how much this would cost.
A.L.
> the database alteration by means of retract and assert* is not
> intended to be particularly efficient
[...]
> This is to plainly say that your code looksccorrect, but neither
> particularly innovative, nor actually efficient.
>
> The lack of efficiency in altering the knowledge base
I am glad you raise the efficiency point - which I also did, but I was
talking about complexity rather. Isn't efficiency a quality of the
implementation of a language, not (necessarily) of the language
itself. Or do you imply that assert* and retract must be necessarily
inefficient in Prolog ?
> > ?- rev([X],[Y]), X == Y. No
> >
> > I have checkd this result in SWI, GNU, XSB, CIAO, ECLIPSE, SICStus
> > and B-Prolog: always the same No.
>
> Whether there was not a rev([a],[a])-like fact in your base, this is
> not surprise. It's a consequence of the closed world hypothesis,
> combined with the inability of Prolog to perform higher order logic
> reasoning, I would say.
First of all, my rev/2 predicate was loaded in the system of course.
Secondly, I would be surprised if the explanation of the No is in CWA
or the HOL reasoning capabilities of Prolog. Maybe you can explain
though ?
> Might I ask how you measured that?
[...]
> Ditto.
["that" being O(n)]
The usual way: repeatedly making the input larger and measuring the
time. I know that I cannot prove an asymptotic linear behaviour in
this way, but this method works often enough. If you have a proof,
that's of course better.
> > 5) ...Hard to believe, but there you go ! Apparently, the added call
> > to rev/2 operates in the same dynamic predicate space as the toplevel
> > call to app/3. For me this almost blew it. Luckily the fix is easy:
> > Prolog should encapsulate its asserts/retracts in a dynamicaly scoped
> > way. Shouldn't be too difficult for Prolog implementors to
> > accomodate for such a nice principle, I'd say.
>
> Here again, the fundamental idea of how the knowledge base is meant to
> be used is key.
Please, can you explain to me "how the knowledge base is meant to be
used" ? This would help me I am sure.
> My understanding of right recursion and left recursion relates to
> grammar production rules and, indirectly, to parser classification,
> but that doesn't fit your statement. Might I ask you to elaborate
> further your conjecture on the "weird programming paradigm"?
The notions of left and right recursion carry over directly from
grammars to Prolog clauses of course.
About "weird programming paradigm": in the beginning there was no
recursion and programming could be understood by most people. It still
can in languages that do not force you to use recursion, like Java:
anybody can program in Java these days, no need to have a PhD in
computer science or a twisted mind when mowing the lawn. But languages
like Prolog force one to use recursion, or rely on syntactic sugar
(like for loops in ECLiPSe) or even worse, you must master things like
maplist. All these options obscure what is really going on.
Finally I would like to ask: why are Prolog masters not EXPLAINING
things instead of mistifying them when newbies appear in this forum ?
Pineapple, the other flea in c.l.prolog's pelt, has complained about
that too.
My blessings,
Because newbies know better.
A.L.
Well, by definition assert *copies* what you assert and (as was pointed
out) therefore you end with list holding copies of the original list.
The traditional reverse/2 implementation does not copy the content of
the list *elements*. That is not only fundamentally faster, but it also
fundamentally different. Otherwise copy_term/2 would not exist :-)
Or do you wish to argue that after my_copy_term below it is allowed
that Copy == Term if Term is not ground?
my_copy_term(Term, Copy) :-
assserta(tmp(Term)),
once(retract(tmp(RawCopy))),
RawCopy = Copy.
Cheers --- Jan
P.s. Wondering how many real newbies are not already asleep after
concluding that Prolog programmers are completely nuts ...