Page 2 of 2

Posted: 16 Sep 2015 8:43
by Thomas Linder Puls
It is of course important to know what we are talking about, but I think the original post explains that very well.

When deciding whether it should be a construction in the language there are several parameters to take into account.

First of all whether it makes sense, which I clearly think the construction does: It is a "pure" logical operation that is faithful to the original declarative/logical reading of the Prolog languages.

Secondly whether it will actually be used, here I have a little more doubt: I guess that Martin that gave the suggestion will use it "extensively", perhaps because he programs more in logical terms than we actually do at PDC (I doubt that we will use it much, if at all, here).

Thirdly, whether alternative code (using already existing constructions) is complex and "unpleasant" or simple and "nice". The alternative code using two negations, comes from the normal logical duality of existential and universal quantifiers: If it is not possible to find "something" that does not fulfils "something", then every thing fulfills "something". Though this is a fundamental property of logic, the code with two nested nots, is both clumsy and unintuitive.
Fourthly it is also necessary to find good syntax for the construction. Good syntax should express the intuition of the semantics. Both so that people that read the code without knowing the construction in complete details, gets the correct idea about what it does, but also so that when they are looking for a construction that does something, they guess that this may be the one that does what they are looking for.

I think this construction qualifies on making sense and not having good alternative code, but I think it disqualifies on usability and syntax (also considering that there exist a mathematical paper that uses for all ... holds ...).

Posted: 16 Sep 2015 11:49
by Martin Meyer
Thomas, OK :-)

Peter, I don't understand your use of dynamic cuts. An equivalent to a foreach-term resp. a forAll-predicate can be coded via a generator-fail-loop without dynamic cuts:

Code: Select all

class predicates     foreach_ : (         function_nd{Type} Gen,         predicate{Type} Body). clauses     foreach_(Gen, Body) :-         Item = Gen(),             Body(Item),             fail.     foreach_(_, _).     class predicates     forAll : (         function_nd{Type} Gen,         predicate_dt{Type} Body)         determ. clauses     forAll(Gen, Body) :-         Item = Gen(),             if not(Body(Item)) then                 !             end if,             fail.     forAll(_, _).
Best regards
Martin

Posted: 16 Sep 2015 17:15
by Peter Muraya
Martin,
I was motivated by the comment from Paul about programming when foreach/do and if/then/else were not available in Prolog. I could not figure out how you would write the forall() without using the dynamic cut.

Posted: 17 Sep 2015 5:43
by Peter Muraya
Martin,
I thought about this a little bit more and found out why you did not understand the dynamic cuts in my code. In the first case, I was not really modelling foreach_() as currently implemented by the foreach/do construct. Your implementation is the correct one.

I revisited the for forAll_() without the dynamic cut and came up with this version, which I think is different from yours. Is it not?

Code: Select all

class predicates     forAll_ : (function_nd{Type} Gen, predicate_dt{Type} Body) determ. clauses     forAll_(Gen, Body) :-         Item = Gen(),         not(Body(Item)),         !,         fail.     forAll_(_, _).

Posted: 17 Sep 2015 12:47
by Martin Meyer
:shock: Ohhh, I had not seen that. Of course your version is the better one.

Many regards
Martin

Posted: 17 Sep 2015 18:31
by Thomas Linder Puls
To complete the circle :-):

Code: Select all

clauses     forAll_(Gen, Body) :-         Item = Gen(),         not(Body(Item)),         !,         fail.     forAll_(_, _).
is the same as

Code: Select all

clauses     forAll_(Gen, Body) :-         Item = Gen(),         not(Body(Item)),         !,         fail         or         succeed.
And since A, !, fail or succeed is the same as not(A) (aka cut-fail-negation) this clause is the same as:

Code: Select all

clauses     forAll_(Gen, Body) :-         not((             Item = Gen(),             not(Body(Item))         )).
Compare this to the very first code:

Code: Select all

not     ((         Gen,             not(DetermBody)     ))

Posted: 18 Sep 2015 5:50
by Peter Muraya
Thomas and Martin,
I'm always learning something new from his forum. cut-fail-negation ... that is news to me. It has helped me understand the following construct which at first was not obvious.

Code: Select all

not     ((         Gen,             not(DetermBody)     ))
You hope that this sort of thing does not happen a lot in your code; otherwise it becomes very difficult to follow for ordinary mortals.