Game semantics

interpret logic as games played between a verifier and a falsifier.

We can use this with proof-search-as-computation

as foundations for interactive and concurrent logic programs.

## Example

We can already write interactive programs in Prolog,

however there are issues.

They can be illustrated by a simple program that asks for user’s name.

`ask_name :-`

`write('What is your name? '), read(Name),`

`write('Hello '), write(Name), nl.`

If you save this text as `"bad_hello.pro"`

, you can have the following query:

`?- consult('bad_hello.pro').`

`?- ask_name.`

`What is your name? foo.`

`Hello foo`

`true.`

Everything seems all right here,

except that we’ve stepped outside from logic programming.

To illustrate I flip the statements around:

`psychic_ask_name :-`

`write('Hello '), write(Name), nl,`

`write('What is your name? '), read(Name).`

This should be acceptable as conjunction is commutative.

Add the text into `"bad_hello.pro"`

, reconsult the file and do the query:

`?- psychic_ask_name.`

`Hello _L155`

`What is your name? wat.`

`true.`

Good try, Prolog!

The original program is not logical to begin with.

Prolog is abusing sequentiality in proof search to provide an additional

imperative programming model into Prolog.

Additive conjunctive quantifiers

allow representation of the same programs logically:

`ask_name :-`

`(∏ write 'What is your name? ') (∏ read Name)`

`(∏ write 'Hello ') (∏ write Name) (∏ nl)`

`true.`

`psychic_ask_name :-`

`(∏ write 'Hello ') (∏ write Name) (∏ nl)`

`(∏ write 'What is your name? ') (∏ read Name)`

`true.`

Prolog interpreter cannot run this program as

it doesn’t have semantics for positive additive quantifiers.

It’s a seemingly minor change,

but the semantics of the program are completely different.

Here’s what should happen:

`?- ask_name.`

`true.`

`What is your name? foo.`

`Hello foo`

`?- psychic_ask_name.`

`false.`

Proof search looks for a strategy to “win” the game that the goal represents.

Technically in the first example we’re

trying to prove something like `∀x∃y.x=y`

.

In the second example we’re trying to prove the opposite `∃x∀y.x=y`

.

The interpreter refuses to run the later program

as it cannot find a strategy where it would “win the game”

that `psychic_ask_name`

is a model of.

To make this all work, the logical formulas

are interpreted as games played between a computer and its environment.

We can also model ordinary games this way

but the results aren’t immediately interesting.

If you model the chess and ask the interpreter to play it,

it will get stuck on the search for a strategy to win the game.

If you ask a game of tic-tac-toe,

it may finish but won’t play because it cannot find a way

to win the game with certainty against any opponent.

However there exists a perfect play of tic-tac-toe that leads to draw or win

that may be found by loosening the constraint that the computer must win the game.

This is also a form of game that the computer cannot win with certainty.

A game of paper-rock-scissors can be modeled with:

`paper_rock_scissors :-`

`(∐ X ∈ [paper, rock, scissors])`

`(∏ Y ∈ [paper, rock, scissors])`

`X = scissors, Y = paper;`

`X = paper, Y = rock;`

`X = rock, Y = scissors.`

Note that by representing it this way we

do not directly model that both players move simultaneously.

Instead, there’s an intermediary that first gets

both players choice before handing out the results.

## Implementation

Since the language has to be extended with quantifiers,

we need a way to handle them.

I think there are two papers that provide the details

needed for implementing this in practice.

- “A Proof Procedure for the Logic of Hereditary Harrop Formulas” – Gopalan Nadathur – 1997
- “Logic programming with bounded quantifiers” – Andrei Voronkov – 1992

The former paper describes how to implement unbounded quantification.

It implements scope for variables by assigning indices for them.

I haven’t understood all the necessities in the later paper so I’m not done yet.

Bounded quantifiers are important for representation of gameplay in logic.

I suppose I won’t try to understand the paper further and just try implementing

the bounded quantifiers through

coroutining.

At first I thought these features could be implemented

through introducing backtracking at success

for positively quantified variables.

Didn’t get that approach to work.

## Heuristics

You can go surprisingly far with just plain brute force.

For example, in tic-tac-toe, if the player crosses the center,

there are only 27600 possible ways the game may play from that point on

and the idea of brute-force searching from the game tree isn’t out of the question.

You need heuristics if you want the computer

to play games where it cannot succeed with certainty.

Fifth generation computer project

attempted to build computers around the concepts of logic programming.

By doing so they introduced concurrent logic programming.

Guarded horn clauses and committed-choice can be seen as an extreme form of

heuristic for dialogical logic programming

where every decision is done without search or prediction.

It may be possible to add support for augmenting the search algorithm itself

with alpha-beta pruning

and negamax search.

While writing this I haven’t yet explored this idea further.

## Foundations and theory

Computability logic

treats logical formulas as games played between two participants.

One participant tries to prove the formula and the other participant tries to refute it.

This logic pivots around the idea that conjunction and disjunction satisfy

De Morgan’s laws

and that there are multiple different logical operators, not just two or four.

Computability logic seem to correspond with

linear Logic.

Deep inference

helps in understanding linear logic.

An idea I haven’t yet examined is the concept that computability logic

allow formulas to share subtrees,

forming directed acyclic graphs instead of tree formulas.

For logic programming the additive and multiplicative linear logic operators

seem to found sufficient foundations that we can build on.

Computability logic allows us to treat variables as quantifications of these operators.

`| parallel | choice`

`conjunction | a ∧ b | a ⊓ b`

`disjunction | a ∨ b | a ⊔ b`

`quantified | parallel | choice`

`conjunction | ∀x. y | ∏x. y`

`disjunction | ∃x. y | ∐x. y`

`Demorgan laws:`

`¬(a ∧ b) = ¬a ∨ ¬b`

`¬(a ∨ b) = ¬a ∧ ¬b`

`¬(a ⊓ b) = ¬a ⊔ ¬b`

`¬(a ⊔ b) = ¬a ⊓ ¬b`

`¬(∀x. y) = ∃x. ¬y`

`¬(∃x. y) = ∀x. ¬y`

`¬(∏x. y) = ∐x. ¬y`

`¬(∐x. y) = ∏x. ¬y`

Parallel operators behave as if two games were played at the same time.

If it’s conjunctive, you have to win both games.

If it’s disjunctive,

you have to win only one of them,

and you can use the other games to win that one.

Choice operators behave as if there was a choice for either player.

Conjunctive choice is a choice of the opponent

whereas the disjunctive choice yours.

Computability logic treats quantifiers as repetition within formulas.

For example the following disjunctively bounded quantified choice formula:

`(∐ X ∈ 0..2) even(X)`

Would be the exactly same as writing:

`even(0) ⊔ even(1) ⊔ even(2)`

All variables in Prolog can be interpreted as this kind of choice-existential

quantifiers such as above.

Binding a variable is similar to doing a choice.

If the choice is wrong, we attempt to backtrack from it

as long as we have other choices we can examine.

We may also present prolog’s disjunction through disjunctive choice:

`even(0).`

`even(s(s(N))) :- even(N).`

Corresponds to:

`even(X) :-`

`X = 0 ⊔ (X = s(s(N)) ∧ even(N)).`

It might be this gives us a sound concept of negation in the language,

but I haven’t concluded that it’d do so because I’m not certain.

For example, the negation of the above one might be:

`¬even(X) :-`

`X != 0 ⊓ (X != s(s(N)) ∨ ¬even(N)).`

There are linear logic programming languages that might reveal how to implement

the parallel disjunction and parallel quantifiers.

## Appendix A: Formulas are types

Prolog has the problem of people commonly not understanding it.

They understand the syntax,

and which logical connectives correspond to what,

and how it’s interpreted,

but not what the programs mean.

Prolog formulas describe types of structures consisting of terms.

For example:

`type foo(X)`

`-----------`

`foo(a)`

`foo(b)`

`foo(c)`

`foo(a(a))`

`foo(a(b))`

`foo(a(c))`

`foo(...)`

Without variables the formulas describe unit types.

Such types have only one value.

For example the following types refer to values of their shape:

`sunny`

`follows(bobby, michael)`

There are also impossible types or contradictions.

For example the following formulas would be such:

`(X = a, X = b)`

`false`

It is impossible to satisfy either of the above constraints.

They describe no values.

Prolog doesn’t allow variables in position such as `X(bobby, michael)`

,

but technically this would not seem to be an issue to support.

Such variable should likely have a structural interpretation,

eg. `X`

is some predicate that gives a true value on `X(bobby, michael)`

and the constraint can be tested when the `X`

is bound.

HOPES seem to be doing this and

Bill Wadge

has written a nice blog post about this idea.

We don’t examine it further in this post.

To solidify this relationship between types and logic program formulas,

lets examine the following Prolog programs:

`nat(0).`

`nat(s(N)) :- nat(N).`

`even(0).`

`even(s(s(N))) :- even(N).`

`odd(s(N)) :- even(N).`

The first predicate describes natural numbers.

`?- nat(N).`

`N = 0 ;`

`N = s(0) ;`

`N = s(s(0)) ;`

`N = s(s(s(0))) ;`

`N = s(s(s(s(0)))) ;`

`N = s(s(s(s(s(0))))) ;`

`N = s(s(s(s(s(s(0)))))) ;`

`N = s(s(s(s(s(s(s(0))))))) ;`

`N = s(s(s(s(s(s(s(s(0)))))))) .`

It’s almost as if we wrote `N ∈ nat`

.

The even and odd predicates work in a similar sense.

If the predicate works,

then the `N`

can only represent a natural number while `nat(N)`

applies to it.

By doing logic programming properly,

you describe all the results that the program may produce.

## Appendix B: Motivation

Interactive form of logic programming,

such as what this dialogic logic programming is,

could allow effortless writing of programs that appear incredibly intelligent.

There is also a slight suggestion that

interactive logic programs could be incredible sort of fun.

After all, if you have a program that plays chess, only chess you can play.

But if you have model of chess with heuristics,

then you can do far much more than just play chess against it.