1

I'm fairly new to Prolog. Anyway, I'm trying to write a recursive set of rules that return the average number of characters per word in a given list of character codes. My code is below.

medellangd(Text,AvgLen) :-
    medellangd(Text,T,1,0,0),
    AvgLen = T.

medellangd([],AvgLen,Space,Words,Chars) :-
    T is (Chars/Words),
    AvgLen = T.
medellangd([A|B],AvgLen,Space,Words,Chars) :-
    succ(Chars,C),
    updatewords(A,Space,Words,W),
    updatespace(A,S),
    medellangd(B,T,S,W,C),
    AvgLen = T.

updatewords(A,1,Words,W) :-
    member(A, [65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122])
    -> succ(Words,S),
       W = S
    ;  W = Words.
updatewords(A,0,Words,W) :-
        W = Words.

updatespace(A,S) :-
    member(A,[65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122])
    -> S = 0
    ;  S = 1.

For reasons which I cannot tell, although AvgLen gets the right value, Prolog returns false when I call medellangd([68,69],AvgLen). When I trace this call, although every call initially is exited before AvgLen gets its value, Prolog decides to redo "(9) updatewords(68, 1, 0, _G2574)" if I enter a semicolon after the AvgLen value assignment, and fails. Why does this happen?

Måns Nilsson
  • 431
  • 1
  • 4
  • 16
  • I am almost sure that your `updatewords/4` is where the choice point is coming from. By the way, I don't understand why you do all these explicit unifications at the end of the predicate definitions.... do you have a reason? –  Sep 17 '16 at 20:47

1 Answers1

1

You predicate is working fine, in order to find a solution prolog tries every possible way, so after giving the answer AvgLen=2 it sercheas for more possible solutions. When Prolog is trying to find a solution it builds a proof tree, where it keeps all the possible ways to prove the goal and try them all one by one until it finds all the right answers and no other ways to prove the goal had left. This is the reason that calls redo, to try more possible solutions. If you want the predicate to be deterministic you could add the cut(!) in:

medellangd(Text,AvgLen) :-
    medellangd(Text,T,1,0,0),
    AvgLen = T,!.

and these will stop when finds the first right answer and will not search further.

A simple example is to understand how prolog works is:

simple_example([]).
simple_example([_]).

The above predicate succeeds if you query simple_example(L). where L is empty or it has one element. Now if you try to query simple_example([]). or simple_example([1]). in trace you will see :

[trace]  ?- simple_example([1]).
   Call: (7) simple_example([1]) ? creep
   Exit: (7) simple_example([1]) ? creep
true.

On the other hand if you write the same example differently:

  simple_example2(L):- L=[].
  simple_example2(L):- L=[_].

The predicate simple_example2 is clearly equivalent to simple_example but if you query simple_example2([]). in trace you will see that because we have [] matches both L in simple_example2 it will try both and of course only first will be right:

[trace]  ?- simple_example2([1]).
   Call: (7) simple_example2([1]) ? Unknown option (h for help)
   Call: (7) simple_example2([1]) ? Unknown option (h for help)
   Call: (7) simple_example2([1]) ? Unknown option (h for help)
   Call: (7) simple_example2([1]) ? creep
   Call: (8) [1]=[] ? creep
   Fail: (8) [1]=[] ? creep
   Redo: (7) simple_example2([1]) ? creep
   Call: (8) [1]=[_G3328] ? creep
   Exit: (8) [1]=[1] ? creep
   Exit: (7) simple_example2([1]) ? creep
true.
coder
  • 12,832
  • 5
  • 39
  • 53
  • Is it possible to algorithmically ensure that there is only one path for Prolog in the proof tree? – Måns Nilsson Sep 17 '16 at 19:09
  • No it doesn't have to do with algorithm but how prolog understands if there are more solutions. This is the main feature of prolog the searching, i will update the answer to explain how prolog would make choice in a very simple example, but in a more complex program it has no point ensuring that prolog will have no other options. Againg if you want only one solution you can use cut. – coder Sep 17 '16 at 19:13
  • Do you have an idea what could cause the fail in my case? – Måns Nilsson Sep 17 '16 at 19:28
  • Should it have a second solution??? If not, if you have write a predicate which solves a problem with one solution then everything else (other searches for solution) should fail. – coder Sep 17 '16 at 19:30
  • I know my algorithm is wrong because medellangd([68,69,91,98,91,91,91,91,97],S) gives S = 3. – Måns Nilsson Sep 17 '16 at 19:35
  • Yes but this doesn't have to do with why prolog tries redo ,your algorithm as it is written returns S=3 for this input and i don't think it should return more so it is normal that prolog tries other sloutions that fail. As for the wrong output try to see what logical error you have by trying different inputs etc... – coder Sep 17 '16 at 19:46
  • The logical error came from counting non-letters as characters in the Chars variable. But I fixed it now. – Måns Nilsson Sep 17 '16 at 21:48
  • I hope my advice/answer was helpful, glad you solved it!! – coder Sep 17 '16 at 21:59