5
votes

I'm currently trying to to interpret user-entered strings via Prolog. I'm using code I've found on the internet, which converts a string into a list of atoms.

"Men are stupid." => [men,are,stupid,'.'] % Example

From this I would like to create a rule, which then can be used in the Prolog command-line.

% everyone is a keyword for a rule. If the list doesn't contain 'everyone'
% it's a fact.

% [men,are,stupid]
% should become ...
stupid(men).

% [everyone,who,is,stupid,is,tall]
% should become ...
tall(X) :- stupid(X).

% [everyone,who,is,not,tall,is,green]
% should become ...
green(X) :- not(tall(X)).

% Therefore, this query should return true/yes:
?- green(women).
true.

I don't need anything super fancy for this as my input will always follow a couple of rules and therefore just needs to be analyzed according to these rules.

I've been thinking about this for probably an hour now, but didn't come to anything even considerable, so I can't provide you with what I've tried so far. Can anyone push me into the right direction?

3
+1 for first converting to atoms! This makes everything that follows a lot more convenient and easier.mat
@lurker: Everyone who's not tall, is green. It isn't stated, that women are tall (therefore they aren't) which means that women are green. To make sure I tried this in SWI-Prolog, which really did yield true.Padarom
@Padarom ah ok, yep, right. :)lurker

3 Answers

5
votes

Consider using a DCG. For example:

list_clause(List, Clause) :-
    phrase(clause_(Clause), List).

clause_(Fact)         --> [X,are,Y], { Fact =.. [Y,X] }.
clause_(Head :- Body) --> [everyone,who,is,B,is,A],
    { Head =.. [A,X], Body =.. [B,X] }.

Examples:

?-  list_clause([men,are,stupid], Clause).
Clause = stupid(men).

?- list_clause([everyone,who,is,stupid,is,tall], Clause).
Clause = tall(_G2763):-stupid(_G2763).

I leave the remaining example as an easy exercise.

You can use assertz/1 to assert such clauses dynamically:

?- List = <your list>, list_clause(List, Clause), assertz(Clause).
2
votes

First of all, you could already during the tokenization step make terms instead of lists, and even directly assert rules into the database. Let's take the "men are stupid" example.

You want to write down something like:

?- assert_rule_from_sentence("Men are stupid.").

and end up with a rule of the form stupid(men).

assert_rule_from_sentence(Sentence) :-
    phrase(sentence_to_database, Sentence).

sentence_to_database -->
    subject(Subject), " ",
    "are", " ",
    object(Object), " ",
    {   Rule =.. [Object, Subject],
        assertz(Rule)
    }.

(let's assume you know how to write the DCGs for subject and object)

This is it! Of course, your sentence_to_database//0 will need to have more clauses, or use helper clauses and predicates, but this is at least a start.

As @mat says, it is cleaner to first tokenize and then deal with the tokenized sentence. But then, it would go something like this:

tokenize_sentence(be(Subject, Object)) -->
    subject(Subject), space,
    be, !,
    object(Object), end.

(now you also need to probably define what a space and an end of sentence is...)

be -->
    "is".
be -->
    "are".

assert_tokenized(be(Subject, Object)) :-
    Fact =.. [Object, Subject],
    assertz(Fact).

The main reason for doing it this way is that you know during the tokenization what sort of sentence you have: subject - verb - object, or subject - modifier - object - modifier etc, and you can use this information to write your assert_tokenized/1 in a more explicit way.

1
votes

Definite Clause Grammars are Prolog's go-to tool for translating from strings (such as your English sentences) to Prolog terms (such as the Prolog clauses you want to generate), or the other way around. Here are two introductions I'd recommend: