# The perils of unground variables in logic

**URL:** <https://swi-prolog.discourse.group/t/the-perils-of-unground-variables-in-logic/652>\
**Category:** General\
**Created:** [May 16, 2019, 3:03pm UTC](https://swi-prolog.discourse.group/t/the-perils-of-unground-variables-in-logic/652 "2019-05-16T15:03:59Z")\
**Posts on this page:** 8\
**Page:** 1

<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:** [May 16, 2019, 3:03pm UTC](https://swi-prolog.discourse.group/t/the-perils-of-unground-variables-in-logic/652/1 "2019-05-16T15:03:59Z")

</div>

I managed to resolve a bug in a program today which was obvious in retrospect, but raised my Prolog enlightenment quite a bit.

The problem starts with a chess program written as part of Stanford University’s General Game Playing course which I discovered via Coursera a few years ago. (The course is still available at [General Game Playing - Notes](http://ggp.stanford.edu/public/notes.php)).

I really enjoyed the course, and I think General Game Playing would have got a lot more traction if the instructor, Professor Michael Genesereth, had simply used Prolog instead of his own invented Lisp-style language called kif.

I was under the impression one could simply transliterate kif into prolog, leading me into the following trap.

The original kif predicate to say a player could move a piece to block a checking move by a queen or a rook (the exact same problem cropped up in the queen or bishop predicate) looked like this:

```nohighlight
; Block rook threat (rook or queen)
(<= (legal ?player (move ?piece ?u ?v ?x ?y))
    (true (control ?player))
    (or (true (check ?player rook ?tx ?ty))
        (true (check ?player queen ?tx ?ty)))
    (not (occupied_by_player ?x ?y ?player))
    (piece_owner_type ?piece ?player ?ptype)
    (distinct ?ptype king)
    (piece_owner_type ?king ?player king)
    (true (cell ?kx ?ky ?king))
    (legal2 ?player (move ?piece ?u ?v ?x ?y))
    (blocks_rook_threat ?x ?y ?tx ?ty ?kx ?ky)
    (not (threatened_with_capture ?player ?tx ?ty ?kx ?ky ?u ?v))	; (u,v) is location moved from -- ignore it
    )

```

My “interpreter” tansliterated it into this:

```prolog
% Block rook threat (rook or queen)
legal(Player, move(Piece, U, V, X, Y)) :- 
  true(control(Player)), 
  (true(check(Player, rook, Tx, Ty)) ; true(check(Player, queen, Tx, Ty))), 
  \+occupied_by_player(X, Y, Player),
  piece_owner_type(Piece, Player, Ptype), 
  dif(Ptype, king), 
  piece_owner_type(King, Player, king), 
  true(cell(Kx, Ky, King)), 
  legal2(Player, move(Piece, U, V, X, Y)), 
  blocks_rook_threat(X, Y, Tx, Ty, Kx, Ky), 
  \+threatened_with_capture(Player, Tx, Ty, Kx, Ky, U, V).

```

It took me a couple of hours to figure out why my game player using the mechanically translated kif rules would not allow players to make blocking moves.

Fixing this simply involved moving one line of code. I’ll leave that here as a chess puzzle for readers.

---

<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:** [May 16, 2019, 3:52pm UTC](https://swi-prolog.discourse.group/t/the-perils-of-unground-variables-in-logic/652/3 "2019-05-16T15:52:10Z")

</div>

The solution here was not deletion, but re-ordering. It’s example of how Prolog is hypothetically a declarative language, but in practice the order of clauses matters a lot.

---

<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:** [May 16, 2019, 4:19pm UTC](https://swi-prolog.discourse.group/t/the-perils-of-unground-variables-in-logic/652/5 "2019-05-16T16:19:34Z")

</div>

True. The basic problem is the occupied\_by\_player predicate always fails because X and Y are only instantiated by the legal2 clause which follows it. The thing I learnt was if you ask if an unground variable is false, it is.

Basic rule of thumb is clauses which set variables need to go at the top, and those that test them at the bottom.

---

<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:** [May 16, 2019, 4:19pm UTC](https://swi-prolog.discourse.group/t/the-perils-of-unground-variables-in-logic/652/6 "2019-05-16T16:19:39Z")

</div>

I’m curious if you could have avoided re-ordering by using [freeze/2](http://www.swi-prolog.org/pldoc/doc_for?object=freeze/2) or the more general [when/2](http://www.swi-prolog.org/pldoc/doc_for?object=when/2).

---

<div class="post-metadata">

**Author:** ![jan](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/jan/32/4_2.png) [@jan](https://swi-prolog.discourse.group/u/jan)\
**Post date:** [May 16, 2019, 4:22pm UTC](https://swi-prolog.discourse.group/t/the-perils-of-unground-variables-in-logic/652/7 "2019-05-16T16:22:27Z")

</div>

> [@joeblog](#):
>
> Prolog is hypothetically a declarative language, but in practice the order of clauses matters a lot

Prolog is a language with a subset that has the same semantics regardless of the ordering. Ordering still affects termination and performance, even in this subset. You use `\+` though, which is is **not** part of this subset. You can extend this subset using _constraints_ (you already use dif/2) and tabling. Be aware though that neither play well with committing to a choice (`!, ->, \+`). In the very latest version (8.1.6), tabling comes with (one form of) sound negation by means of [tnot/1](http://www.swi-prolog.org/pldoc/doc_for?object=tnot/1).

---

<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:** [May 16, 2019, 4:54pm UTC](https://swi-prolog.discourse.group/t/the-perils-of-unground-variables-in-logic/652/9 "2019-05-16T16:54:25Z")

</div>

“Prolog is different, but it’s not that different.” – Richard O’ Keefe

---

<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:** [May 16, 2019, 4:59pm UTC](https://swi-prolog.discourse.group/t/the-perils-of-unground-variables-in-logic/652/10 "2019-05-16T16:59:00Z")

</div>

Generate-and-test can be very slow if there are a lot of possibilities. A faster way can be to use delayed-test-and-generate, using either freeze/2 (or when/2) or tnot/1. This can short-circuit some of the generating, when a test is sufficiently ground to be decidable as having failed. (See also “constraints”)

---

<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:** [May 16, 2019, 5:03pm UTC](https://swi-prolog.discourse.group/t/the-perils-of-unground-variables-in-logic/652/11 "2019-05-16T17:03:44Z")

</div>

Thanks Peter. At some stage I’d like to write an interpreter for the library of General Game Playing rules created by Stanford and Dresden universities which would automatically avoid bugs like this. I’ve little experience with the clauses you mention, so will look into them.
