# Write A Prolog Rule

**URL:** <https://swi-prolog.discourse.group/t/write-a-prolog-rule/2164>\
**Category:** Help!\
**Created:** [April 13, 2020, 7:08pm UTC](https://swi-prolog.discourse.group/t/write-a-prolog-rule/2164 "2020-04-13T19:08:39Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![joefrank97](https://avatars.discourse-cdn.com/v4/letter/j/f4b2a3/32.png) [@joefrank97](https://swi-prolog.discourse.group/u/joefrank97)\
**Post date:** [April 13, 2020, 7:08pm UTC](https://swi-prolog.discourse.group/t/write-a-prolog-rule/2164/1 "2020-04-13T19:08:39Z")

</div>

can you say no u properly

---

<div class="post-metadata">

**Author:** ![EricGT](https://avatars.discourse-cdn.com/v4/letter/e/f1d935/32.png) [@EricGT](https://swi-prolog.discourse.group/u/EricGT)\
**Post date:** [April 13, 2020, 7:41pm UTC](https://swi-prolog.discourse.group/t/write-a-prolog-rule/2164/2 "2020-04-13T19:41:57Z")

</div>

> [@joefrank97](#):
>
> Also, are these kinds of posts acceptable on this forum?

Yes

How is distance defined?

---

<div class="post-metadata">

**Author:** ![joefrank97](https://avatars.discourse-cdn.com/v4/letter/j/f4b2a3/32.png) [@joefrank97](https://swi-prolog.discourse.group/u/joefrank97)\
**Post date:** [April 13, 2020, 7:44pm UTC](https://swi-prolog.discourse.group/t/write-a-prolog-rule/2164/3 "2020-04-13T19:44:27Z")

</div>

Whatever basic way you can think of? Let’s say there’s a 5 by 5 grid and each square is 1 foot

---

<div class="post-metadata">

**Author:** ![EricGT](https://avatars.discourse-cdn.com/v4/letter/e/f1d935/32.png) [@EricGT](https://swi-prolog.discourse.group/u/EricGT)\
**Post date:** [April 13, 2020, 7:47pm UTC](https://swi-prolog.discourse.group/t/write-a-prolog-rule/2164/4 "2020-04-13T19:47:55Z")

</div>

> [@joefrank97](#):
>
> Whatever basic way you can think of?

These are the basic ways I think of measuring distance, see: [Metric](https://en.wikipedia.org/wiki/Metric_(mathematics))

---

<div class="post-metadata">

**Author:** ![joefrank97](https://avatars.discourse-cdn.com/v4/letter/j/f4b2a3/32.png) [@joefrank97](https://swi-prolog.discourse.group/u/joefrank97)\
**Post date:** [April 13, 2020, 9:14pm UTC](https://swi-prolog.discourse.group/t/write-a-prolog-rule/2164/5 "2020-04-13T21:14:09Z")

</div>

sure! How would I implement that by making a prolog program?

---

<div class="post-metadata">

**Author:** ![EricGT](https://avatars.discourse-cdn.com/v4/letter/e/f1d935/32.png) [@EricGT](https://swi-prolog.discourse.group/u/EricGT)\
**Post date:** [April 13, 2020, 11:51pm UTC](https://swi-prolog.discourse.group/t/write-a-prolog-rule/2164/7 "2020-04-13T23:51:40Z")

</div>

> [@joefrank97](#):
>
> How would I implement that by making a prolog program?

```prolog
discrete_metric(a(X,Y),b(X,Y),0) :- !.
discrete_metric(a(X1,_),b(X2,_),1) :-
    X1 \= X2 , !.
discrete_metric(a(_,Y1),b(_,Y2),1) :-
    Y1 \= Y2.

% Enhanced based on comment by Peter

euclidean_metric(a(X1,Y1),b(X2,Y2),Distance) :-
    X is abs(X2 - X1),
    Y is abs(Y2 - Y1),
    (
        X == 0
    ->
        Distance is float(Y)
    ;
        (
            Y == 0
        ->
            Distance is float(X)
        ;
            Distance is sqrt(X **2 + Y** 2)
        )
    ).

taxicab_metric(a(X1,Y1),b(X2,Y2),Distance) :-
    X is abs(X2 - X1),
    Y is abs(Y2 - Y1),
    Distance is X + Y.

```

Test cases

```prolog
:- begin_tests(metrics).

discrete_metric_case(a(0,0),b(0,0),0).
discrete_metric_case(a(1,0),b(0,0),1).
discrete_metric_case(a(0,1),b(0,0),1).
discrete_metric_case(a(0,0),b(1,0),1).
discrete_metric_case(a(0,0),b(0,1),1).
discrete_metric_case(a(2,3),b(4,5),1).

euclidean_metric_case(a(0,0),b(0,0),0.0).
euclidean_metric_case(a(1,0),b(0,0),1.0).
euclidean_metric_case(a(0,1),b(0,0),1.0).
euclidean_metric_case(a(0,0),b(1,0),1.0).
euclidean_metric_case(a(0,0),b(0,1),1.0).
euclidean_metric_case(a(2,3),b(4,5),2.8284271247461903).

taxicab_metric_case(a(0,0),b(0,0),0).
taxicab_metric_case(a(1,0),b(0,0),1).
taxicab_metric_case(a(0,1),b(0,0),1).
taxicab_metric_case(a(0,0),b(1,0),1).
taxicab_metric_case(a(0,0),b(0,1),1).
taxicab_metric_case(a(2,3),b(4,5),4).

test(discrete_metric,[forall(discrete_metric_case(P1,P2,Distance))]) :-
    discrete_metric(P1,P2,Distance).

test(euclidean_metric,[forall(euclidean_metric_case(P1,P2,Distance))]) :-
    euclidean_metric(P1,P2,Distance).

test(taxicab_metric,[forall(taxicab_metric_case(P1,P2,Distance))]) :-
    taxicab_metric(P1,P2,Distance).

:- end_tests(metrics).

```

Example run.

```prolog
?- make.
% c:/users/groot/documents/projects/prolog/swi-discourse_039 compiled 0.00 sec, 0 clauses
% PL-Unit: metrics .................. done
% All 18 tests passed
true.

```

---

<div class="post-metadata">

**Author:** ![peter.ludemann](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/peter.ludemann/32/48_2.png) [@peter.ludemann](https://swi-prolog.discourse.group/u/peter.ludemann)\
**Post date:** [April 14, 2020, 12:05am UTC](https://swi-prolog.discourse.group/t/write-a-prolog-rule/2164/8 "2020-04-14T00:05:31Z")

</div>

> [@EricGT](#):
>
> Distance is Y \* 1.0

Or: `Distance is float(Y)`

---

<div class="post-metadata">

**Author:** ![EricGT](https://avatars.discourse-cdn.com/v4/letter/e/f1d935/32.png) [@EricGT](https://swi-prolog.discourse.group/u/EricGT)\
**Post date:** [April 14, 2020, 12:13am UTC](https://swi-prolog.discourse.group/t/write-a-prolog-rule/2164/9 "2020-04-14T00:13:32Z")

</div>

> [@peter.ludemann](#):
>
> Or: `Distance is float(Y)`

When writing the code I thought that and did a quick check by Googling and found [float/1](https://www.swi-prolog.org/pldoc/man?predicate=float/1) when I should have been looking for [float/1](https://www.swi-prolog.org/pldoc/man?function=float/1).

For those not paying attention like me at the time, one is a predicate and one is function. 🧐

---

<div class="post-metadata">

**Author:** ![joeblog](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/joeblog/32/122_2.png) [@joeblog](https://swi-prolog.discourse.group/u/joeblog)\
**Post date:** [April 14, 2020, 8:10am UTC](https://swi-prolog.discourse.group/t/write-a-prolog-rule/2164/10 "2020-04-14T08:10:06Z")

</div>

A simple predicate to return the Cartesian distance between x0, y0 and x1, y1 could look something like.

```prolog
distance(X0, Y0, X1, Y1, Dx, Dy) :-
    Dx is abs(X1 - X0),
    Dy is abs(Y1 - Y0).

```

To check if x1, y1 is within the allowed distance maxdx, maxdy from x0, y0 you could use this with say

```prolog
allowed_distance(Dx, Dy, MaxDx, MaxDy) :-
    Dx =< MaxDx,
    Dy =< MaxDy.

```

And then the problem could be solved with:

```prolog
distance(X0, Y0, X1, Y1, Dx, Dy), allowed_distance(Dx, Dy, MaxDx, MaxDy).

```

A basic concept of Prolog which I certainly struggled with initially is that instead of

```prolog
f(x) = y

```

you have `f(x,y)` which in the documentation would be written something like `f(+X:type, -Y:type)` to indicate X is an input and Y an output.

For arithmetic functions, SWI Prolog offers a choice of Prolog-style and “traditional” function style: eg there is an [**abs** (+Number, -Absolute)](https://www.swi-prolog.org/pldoc/doc_for?object=quintus%3Aabs/2) which returns the absolute value as an output argument or [**abs** (+Expr)](https://www.swi-prolog.org/pldoc/doc_for?object=f(abs/1)) which can only be used in [is](https://www.swi-prolog.org/pldoc/doc_for?object=(is)/2) clauses as in `Y is abs(3 - 2)`.

---

<div class="post-metadata">

**Author:** ![joefrank97](https://avatars.discourse-cdn.com/v4/letter/j/f4b2a3/32.png) [@joefrank97](https://swi-prolog.discourse.group/u/joefrank97)\
**Post date:** [April 14, 2020, 4:43pm UTC](https://swi-prolog.discourse.group/t/write-a-prolog-rule/2164/11 "2020-04-14T16:43:32Z")

</div>

Thanks for those who posted! I am learning

---

<div class="post-metadata">

**Author:** ![EricGT](https://avatars.discourse-cdn.com/v4/letter/e/f1d935/32.png) [@EricGT](https://swi-prolog.discourse.group/u/EricGT)\
**Post date:** [April 14, 2020, 4:49pm UTC](https://swi-prolog.discourse.group/t/write-a-prolog-rule/2164/12 "2020-04-14T16:49:04Z")

</div>

> [@joefrank97](#):
>
> Pythagorean Theorem ([Wikipedia](https://en.wikipedia.org/wiki/Pythagorean_theorem))

```prolog
Distance is sqrt(X **2 + Y** 2)

```

🤔

---

<div class="post-metadata">

**Author:** ![joefrank97](https://avatars.discourse-cdn.com/v4/letter/j/f4b2a3/32.png) [@joefrank97](https://swi-prolog.discourse.group/u/joefrank97)\
**Post date:** [April 14, 2020, 4:52pm UTC](https://swi-prolog.discourse.group/t/write-a-prolog-rule/2164/13 "2020-04-14T16:52:25Z")

</div>

I apologize, I had misunderstood the \*\*. Should I delete my recent reply?

However, this begs a good question. Prolog, admittedly, doesn’t have as big of resources as say Java or C like I’m used to. How would you advise looking up things like \*\* besides just googling? Are there specific sites that are helpful? When I want to research something specific Prolog, what is the best way to do so?

---

<div class="post-metadata">

**Author:** ![EricGT](https://avatars.discourse-cdn.com/v4/letter/e/f1d935/32.png) [@EricGT](https://swi-prolog.discourse.group/u/EricGT)\
**Post date:** [April 14, 2020, 5:06pm UTC](https://swi-prolog.discourse.group/t/write-a-prolog-rule/2164/14 "2020-04-14T17:06:15Z")

</div>

> [@joefrank97](#):
>
> Are there specific sites that are helpful?

With regards to Prolog I don’t know any better than this one, but am all ears if someone has something else.

> [@joefrank97](#):
>
> How would you advise looking up things like \*\* besides just googling?

Unlike other programming languages where you can typically Google for something, with Prolog it comes more from experience and actually doing a class and working through the few classic books. (free [books](https://stackoverflow.com/tags/prolog/info) which doesn’t include many of the classics). If you look back in my other post it notes that I often read sections of those books about every month looking for more details on to refresh my memory on how to think about doing it in Prolog. Because Prolog is basically built on top of just unification, it is just a matter of understanding a few basic concepts and applying them. At the abstract level this is pretty standard in Prolog, but when you get closer to the metal, e.g. OS and such, then knowing which predicates to used can often be found in the documentation.

One place I often look for examples is in the SWI-Prolog source code posted on [GitHub](https://github.com/SWI-Prolog).

Another repository with SWI-Prolog code is in the [packages](https://www.swi-prolog.org/pack/list)

> [@joefrank97](#):
>
> When I want to research something specific Prolog, what is the best way to do so?

Try something and see if it works and then ask questions if stuck. If you read the current [post](https://swi-prolog.discourse.group/u/emacstheviking/activity) by @emacstheviking you can see another with the same need.

---

<div class="post-metadata">

**Author:** ![joefrank97](https://avatars.discourse-cdn.com/v4/letter/j/f4b2a3/32.png) [@joefrank97](https://swi-prolog.discourse.group/u/joefrank97)\
**Post date:** [April 14, 2020, 5:13pm UTC](https://swi-prolog.discourse.group/t/write-a-prolog-rule/2164/15 "2020-04-14T17:13:50Z")

</div>

Thanks! I’ll look into the GitHub, keep working on problems on my own, ask questions here, etc. I’m a slow learner, but programming is really fun.

Again, new to the forum. Should I mark one of these answers as “solution” and then somehow close the thread?

---

<div class="post-metadata">

**Author:** ![EricGT](https://avatars.discourse-cdn.com/v4/letter/e/f1d935/32.png) [@EricGT](https://swi-prolog.discourse.group/u/EricGT)\
**Post date:** [April 14, 2020, 5:19pm UTC](https://swi-prolog.discourse.group/t/write-a-prolog-rule/2164/16 "2020-04-14T17:19:07Z")

</div>

> [@joefrank97](#):
>
> Again, new to the forum. Should I mark one of these answers as “solution” and then somehow close the thread?

You can but others don’t.

Also I don’t think these can be closed. This is not like StackOverflow where every topic is a question and can only have an answer. Some post take on a life of there own and go on for days, e.g. [Start of IEEE 754 support](https://swi-prolog.discourse.group/t/start-of-ieee-754-support/1843)

---

<div class="post-metadata">

**Author:** ![joefrank97](https://avatars.discourse-cdn.com/v4/letter/j/f4b2a3/32.png) [@joefrank97](https://swi-prolog.discourse.group/u/joefrank97)\
**Post date:** [April 14, 2020, 5:59pm UTC](https://swi-prolog.discourse.group/t/write-a-prolog-rule/2164/17 "2020-04-14T17:59:13Z")

</div>

Hi Eric,

Sorry, know you’re probably pretty busy. I was just wondering if you’d be able to add comments to your code just so I can make sure I really understand what each line is doing. If you can’t, no big deal.

---

<div class="post-metadata">

**Author:** ![EricGT](https://avatars.discourse-cdn.com/v4/letter/e/f1d935/32.png) [@EricGT](https://swi-prolog.discourse.group/u/EricGT)\
**Post date:** [April 14, 2020, 6:19pm UTC](https://swi-prolog.discourse.group/t/write-a-prolog-rule/2164/18 "2020-04-14T18:19:42Z")

</div>

> [@joefrank97](#):
>
> I was just wondering if you’d be able to add comments to your code just so I can make sure I really understand what each line is doing. If you can’t, no big deal.

It is pretty basic code without anything tricky so really doesn’t need comments. Don’t get me wrong thinking that I am against comments, I am all for them when needed.

Instead it would be better if you asked about what you don’t understand, then I or others can answer those questions individually. But before asking look in [Learn Prolog Now!](http://www.learnprolognow.org/) or one of the [free books](https://stackoverflow.com/tags/prolog/info) or [classic books](https://swi-prolog.discourse.group/t/useful-prolog-references/1089). Also if you are serious about learning Prolog then get one or more of the classic books.

---

<div class="post-metadata">

**Author:** ![EricGT](https://avatars.discourse-cdn.com/v4/letter/e/f1d935/32.png) [@EricGT](https://swi-prolog.discourse.group/u/EricGT)\
**Post date:** [April 14, 2020, 8:48pm UTC](https://swi-prolog.discourse.group/t/write-a-prolog-rule/2164/20 "2020-04-14T20:48:00Z")

</div>

> [@joefrank97](#):
>
> ```prolog
> safe(Distance,(X1,Y1),(X2,Y2)) :-
> 
> Distance =< sqrt((Y2-Y1)**2 + (X2-X1)**2).
> 
> ```
> 
> Does this look like a good solution? Or am I missing something?

You should create some test cases and try locations with one or more zero coordinates; if you don’t know why you have something to learn.

Also you don’t add blank lines in a predicate and should indent after the head of the predicate, e.g.

```prolog
safe(Distance,(X1,Y1),(X2,Y2)) :-
    Distance =< sqrt((Y2-Y1)**2 + (X2-X1)**2).

```

---

<div class="post-metadata">

**Author:** ![joefrank97](https://avatars.discourse-cdn.com/v4/letter/j/f4b2a3/32.png) [@joefrank97](https://swi-prolog.discourse.group/u/joefrank97)\
**Post date:** [April 14, 2020, 8:50pm UTC](https://swi-prolog.discourse.group/t/write-a-prolog-rule/2164/21 "2020-04-14T20:50:53Z")

</div>

Thanks for the tips on formatting.

---

<div class="post-metadata">

**Author:** ![EricGT](https://avatars.discourse-cdn.com/v4/letter/e/f1d935/32.png) [@EricGT](https://swi-prolog.discourse.group/u/EricGT)\
**Post date:** [April 14, 2020, 8:59pm UTC](https://swi-prolog.discourse.group/t/write-a-prolog-rule/2164/22 "2020-04-14T20:59:22Z")

</div>

> [@joefrank97](#):
>
> It works with zero coordinates, did you notice something?

No I didn’t notice anything, but you should always check the corner cases and create test cases. It is a good habit to get into from the start so that when you get to larger projects writing test cases will not be added surprise and if you have proper test cases, the moment something is wrong you will know it versus spending days looking for a bug because the test cases were not compete.
