// Abstract ------------------------------------------------------------------------------------------------------------------------------

This sample shows how a "conversation" around simple inferences on relational data can be created/managed. It is based on LINNEUS by Steven Tanimoto in his book "The Elements of Artificial Intelligence Using Common Lisp".

// Examples ------------------------------------------------------------------------------------------------------------------------------

?- #linneus("what is a turbot",:s)
-> ( "turbot is a fish, fish is an animal" ) := 1.00 (0.009) 1
-> ( "turbot is a fish, fish is a swimmer" ) := 1.00 (0.010) 2
?- #linneus("what is a swimmer",:s)
-> ( "a swimmer is something more generic than a fish" ) := 1.00 (0.007) 1
?- #linneus("is a turbot an animal",:s)
-> ( "yes" ) := 1.00 (0.013) 1
?- #linneus("is a turbot a dog",:s)
-> ( "no" ) := 1.00 (0.016) 1
?- #linneus("why is a turbot a swimmer",:s)
-> ( "because turbot is a fish, fish is a swimmer" ) := 1.00 (0.015) 1
?- #linneus("why is a turbot a fish",:s)
-> ( "because i was told so" ) := 1.00 (0.009) 1
?- #linneus("is a turbot a turbot",:s)
-> ( "yes, they are identical" ) := 1.00 (0.008) 1
?- #linneus("a plant is an organism",:s)
-> ( "okay" ) := 1.00 (0.006) 1
?- #linneus("an animal is an organism",:s)
-> ( "okay" ) := 1.00 (0.006) 1
?- #linneus("an invertebrate is an animal",:s)
-> ( "okay" ) := 1.00 (0.006) 1
?- #linneus("an mollusk is an invertebrate",:s)
-> ( "okay" ) := 1.00 (0.006) 1
?- #linneus("an anthropod is an invertebrate",:s)
-> ( "okay" ) := 1.00 (0.007) 1
?- #linneus("an insect is an anthropod",:s)
-> ( "okay" ) := 1.00 (0.006) 1
?- #linneus("an butterfly is an insect",:s)
-> ( "okay" ) := 1.00 (0.006) 1
?- #linneus("a moth is an insect",:s)
-> ( "okay" ) := 1.00 (0.006) 1
?- #linneus("why is a moth an animal",:s)
-> ( "because moth is a insect, insect is a anthropod, anthropod is a invertebrate, invertebrate is a animal" ) := 1.00 (0.023) 1
?- #linneus("what animal is there",:s)
-> ( "there is dog, cat, fish and invertebrate" ) := 1.00 (0.311) 1
 
// Code ----------------------------------------------------------------------------------------------------------------------------------

isa {class = MRKCLettered, no.match = fail } { // knowledge holder (filled with a couple of relations to get started)

    (dog, animal);
    (cat, animal);
    (turbot, fish);
    (fish, animal);
    (fish, swimmer);

}

str2sym { // transforms all strings in a list into symbols

    ([],[]);
    ([:h|:r],[:h.s|:r.s]) :- str.tosym(:h,:h.s), #str2sym(:r,:r.s);

}

s2ls { // tokenize a string and transforms it into a list of symbols

    (:s,:lo) :- str.tokenize(:s," ",:l), #str2sym(:l,:lo);

}

add.article { // add the right article based on he first letter of a word

    (:si,:so) :- sym.sub(:si,0,1,_?[lst.member([a,e,i,o,u])]), str.cat("an ",:si,:so);
    (:si,:so) :- sym.sub(:si,0,1,_?[lst.except([a,e,i,o,u])]), str.cat("a ",:si,:so);

}

match.article { // match any symbol that can be interpreted as as 'article'

    (:x) :- lst.member(:x,[a,an,the,that,this,those,these]);

}

match.statement { // match a statement (such as "a dog is an animal")

    ([:a,:x,is,:b,:y],:x,:y)^   :- #match.article(:a), #match.article(:b);
    ([:x,is,:y],:x,:y)^         :- #match.article(:a);

}

match.enum { // match an enumeration query (such as "what animal is there")

    ([what,:x,is,there],:x) :- true;

}

match.question { // match a question (such as "what is a turbot")

    ([what,is,:x],:x)^      :- true;
    ([what,is,:a,:x],:x)^   :- #match.article(:a);

}

match.check { // match a check type of question (such as "is a turbot a fish")

    ([is,:a,:x,:b,:y],:x,:y)^ :- #match.article(:a), #match.article(:b);
    ([is,:x,:a,:y],:x,:y)     :- #match.article(:a);

}

match.why { // match a why type question (such as "why is a turbot a fish")

    ([why,is,:a,:x,:b,:y],:x,:y)^ :- #match.article(:a), #match.article(:b);

}

format.answer { // format a string answer based on a string of "isa" links

    ([],"")^        :- true;
    ([:a,:b],:s)^   :- #add.article(:b,:b2), str.cat(:a," is ",:b2,:s);
    ([:a,:b|:r],:s) :- #format.answer([:b|:r],:s1), #add.article(:b,:b2), str.cat(:a," is ",:b2,", ",:s1,:s);

    ([],:e,"")^         :- true;
    ([:a,:e],:e,:s)^    :- #add.article(:e,:e2), str.cat(:a," is ",:e2,:s);
    ([:a,:e|:r],:e,:s)  :- #add.article(:e,:e2), str.cat(:a," is ",:e2,:s);
    ([:a,:b|:r],:e?[neq(:b)],:s) :- #format.answer([:b|:r],:e,:s1), #add.article(:b,:b2),
                                    str.cat(:a," is ",:b2,", ",:s1,:s);

}

format.enum { // format a string answer based on a list of enums

    ([],"")^        :- true;
    ([:e],:s)^      :- str.cat(:e,:s);
    ([:h,:t],:s)^   :- str.cat(:h," and ",:t,:s);
    ([:h|:t],:s)^   :- #format.enum(:t,:s1), str.cat(:h,", ",:s1,:s);

}

isa.link { // create a list that contains all the linked 'isa' relationships

    (:x,[:x|:l]) :-  #isa(:x,:y), #isa.link(:y,:l);
    (:x,[:x])    :- !#isa(:x,_);

}

linneus { //main

    (:i,:o)    :- #s2ls(:i,:l), #linneus.proc(:l,:o);

}

linneus.proc { // main "procedure", matchs user input and executes

    ([bye],"goodbye")^              :- true;

    (:l,"okay")                     :- #match.statement(:l,:o,:c), assert(isa(:o,:c));

    (:l,:s)                         :- #match.question(:l,:x),  #isa.link(:x,:link)^, #format.answer(:link,:s);
    (:l,:s)                         :- #match.question(:l,:x),  #isa(:c,:x)^, #add.article(:c,:c2),
                                       str.cat("a ",:x," is something more generic than ",:c2,:s);
    (:l,"i don't know")             :- #match.question(:l,:x), !#isa(:x,_), !#isa(_,:x);

    (:l,"yes, they are identical")  :- #match.check(:l,:x,:x);
    (:l,"yes")                      :- #match.check(:l,:x,:y), neq(:x,:y), #isa.link(:x,:link),
                                       lst.length(:link,_?[gt(1)]), lst.member(:y,:link)^;
    (:l,"no")                       :- #match.check(:l,:x,:y), neq(:x,:y), #isa.link(:x,:link),
                                       lst.length(:link,_?[gt(1)]), !lst.member(:y,:link)^;
    (:l,"i don't know")             :- #match.check(:l,:x,:y), neq(:x,:y), !#isa(:x,_);

    (:l,:s)                         :- #match.enum(:l,:x), #isa(_,:x), #fzz.collect([],isa(\:y,:x),_,{tmo=0.1}),
                                       #format.enum(:y,:s1), str.cat("there is ",:s1,:s);
    (:l,"i don't know")             :- #match.enum(:l,:x), !#isa(_,:x);

    (:l,"because i was told so")    :- #match.why(:l,:x,:y), #isa(:x,:y)^;
    (:l,"i don't know")             :- #match.why(:l,:x,:y), !#isa(:x,_)^;
    (:l,:s)                         :- #match.why(:l,:x,:y), #isa.link(:x,:link), lst.length(:link,_?[gt(1)]),
                                       lst.member(:y,:link), #format.answer(:link,:y,:s1), str.cat("because ",:s1,:s);
    (:l,"i don't know")             :- #match.why(:l,:x,:y), #isa.link(:x,:link), lst.length(:link,_?[lte(1)]);

}

// ---------------------------------------------------------------------------------------------------------------------------------------

[Home] [Email] [Twitter] [LinkedIn]