2

I have an assigment for school, started learning Prolog recently.
This is the exercise (pretty straightforward):

Write a program in Prolog to find a length of a given list. For example, length([a, b, c, d, e]). should print 5

I really have no clue how to create a length/1 predicate that does this for me. This is the code I have:

length([],0).
length([_|T],N) :- length(T,X), N is X+1. 

Now, I asked my teacher how to turn this to a length/1 predicate, and he told me to use the write/1 predicate. I looked up the write/1 predicate, but I don't see how this will help me writing a length/1 predicate. Any tips/tricks to do this?
To be clear, this is homework.

repeat
  • 18,496
  • 4
  • 54
  • 166
Kes
  • 47
  • 4
  • 3
    There's no trick. A `length/1` predicate is far less useful than a `length/2` predicate. Normally, you would do, `length([1,2,3], N), write(N), nl.` You could easily turn that into a `length/1` predicate if you want. It's a bit disconcerting the principles they seem to teaching in Prolog courses. They seem to teach Prolog as an obtuse and limited imperative language instead of the simple yet powerful relational language that it is. – lurker Nov 25 '15 at 15:55
  • 2
    Good comment, +1! I used to see this exactly the same way, until @repeat pointed out one interesting thing to me: If you look at people that teach and use Prolog despicably, one often sees that they are very happy even though they only use a tiny fraction of the language's actual abilities. Since then, I have come to adopt a slightly different interpretation of this: Even though they lose out on so much, they are already extremely happy with what little they have! In the future, they will likely be even happier with more general features (constraints etc.) that are becoming more widely known! – mat Nov 25 '15 at 16:08

2 Answers2

4

The solution is easy: impure(Ls) :- length(Ls, L), write(L)..

However, this is a very bad idea for several reasons.

A very important one is that things that appear only on your screen cannot be reasoned about within Prolog!

Thus, if you just write some results with write/1, you cannot really run automatic test cases to see whether your predicate actually behaves as expected. At least writing tests becomes much harder this way.

In contrast, with your original, purer version of the code (which did not use side-effects), you can easily test for example:

?- length([a,b,c], 3).
true.

and also run several such test cases automatically, and use Prolog to see whether they succeed. For example, a batch of 10,000 test cases may look like (searching for counterexamples):

?- between(1, 10_000, L), length(Ls, L),  length([_|Ls], L1), L1 =\= L+1.
false.

In contrast, how do you test an impure predicate?

?- between(1, 10_000, L), length(Ls, L),  impure([_|Ls])  what now??

As you see, it is really hard to reason about the output of a predicate!

Also, this makes your predicate much less general than your current version! You can no longer use the impure version in other directions. For example, how do you now generate a list of given length? There is no way to supply the length!

Stay pure folks, and use the Prolog toplevel to obtain answers instead of writing them yourselves on the screen!

mat
  • 40,498
  • 3
  • 51
  • 78
2

TL;DR: Don't!

What you want definitely is do-able in Prolog, but ask yourself "Should I do it like that?".

My advice to you on how to proceed is:

  1. Don't use Prolog's low-level I/O API (write/1, nl/0, ...) as it is based on .

  2. Use ! Start by reading this fine Prolog primer on definite clause grammars.

  3. Get acquainted with (and use!) the .

repeat
  • 18,496
  • 4
  • 54
  • 166