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

This sample simulates a Rogerian psychiatrist and is based on SHRINK (by Steven Tanimoto in his book "The Elements of Artificial Intelligence Using Common Lisp"), it-self inspired by J. Weizenbaum's ELIZA program.

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

?- #shrink("hello")
-> ( ) := 0.00 (0.002) 1
please go on
-> ( ) := 1.00 (0.004) 2
?- #shrink("i have a problem")
how long have you had a problem
-> ( ) := 1.00 (0.006) 1
?- #shrink("not that long")
-> ( ) := 0.00 (0.006) 1
tell me more
-> ( ) := 1.00 (0.009) 2
?- #shrink("i am not sure this project will ever be over")
-> ( ) := 0.00 (0.013) 1
i see
-> ( ) := 1.00 (0.016) 2
?- #shrink("it has been a long road")
-> ( ) := 0.00 (0.008) 1
what does that indicates
-> ( ) := 1.00 (0.010) 2
?- #shrink("that it was not easy")
-> ( ) := 0.00 (0.007) 1
but why be concerned about it
-> ( ) := 1.00 (0.009) 2
?- #shrink("no but")
-> ( ) := 0.00 (0.004) 1
dont be so negative
-> ( ) := 1.00 (0.005) 2
?- #shrink("okay")
-> ( ) := 0.00 (0.004) 1
just tell me how you feel
-> ( ) := 1.00 (0.006) 2
?- #shrink("tired")
-> ( ) := 0.00 (0.004) 1
please go on
-> ( ) := 1.00 (0.006) 2
?- #shrink("bye")
goodbye
-> ( ) := 1.00 (0.003) 1
 
// Code ----------------------------------------------------------------------------------------------------------------------------------

// cycle through a list of words at each successive calls
wword {

    index = 0,
    words = [when, why, where, how]

} {

    // the prototype will reset the index to 0 if its value is the size of the words list
    (:w) :- peek(index,:i),
            peek(words,:l),
            lst.length(:l,:s),
            eq(:i,:s),
            poke(index,0),
            false;

    // the main prototype
    (:w) :- peek(index,:i),
            peek(words,:l),
            lst.item(:l,:i,:w),
            add(:i,1,:i2),
            poke(index,:i2);

}

// unifies if the symbol is one in a list
wpred {

    words = [when, why, where, how]

} {


    (:w) :- peek(words,:l), lst.member(:w,:l);

}

// unifies if the symbol is one in a list
dpred {

    words = [do, can, should, would]

} {


    (:w) :- peek(words,:l), lst.member(:w,:l);

}

// cycle through a list of default responses at each successive calls
punts {

    index = 0,
    punts = [

        "please go on",
        "tell me more",
        "i see",
        "what does that indicates",
        "but why be concerned about it",
        "just tell me how you feel"

    ]

} {

    // the prototype will reset the index to 0 if its value is the size of the punts list
    (:w) :- peek(index,:i),
            peek(punts,:l),
            lst.length(:l,:s),
            eq(:i,:s),
            poke(index,0),
            false;

    // the main prototype
    (:w) :- peek(index,:i),
            peek(punts,:l),
            lst.item(:l,:i,:w),
            add(:i,1,:i2),
            poke(index,:i2);

}

// transforms words from 1st to 2nd person (or vice versa)
you.me {

    (i,you);
    (me,you);
    (you,me);
    (my,your);
    (your,my);
    (yours,mine);
    (mine,yours);
    (am,are);
    (:o,:o);

}

// unifies with a list of verbs
verbp {

    words = [ go, have, be, try, eat, take, help, make, get, jump, write,
              type, fill, put, turn, compute, think, blink, crash, crunch,
              add ]

} {


    (:w) :- peek(words,:l), lst.member(:w,:l);

}

// transforms all words in a list from 1st to 2nd person (or vice versa)
you.me.map {

    ([],[]);
    ([:h|:r],[:h.s|:r.s]) :- #you.me(:h,:h.s), #you.me.map(:r,:r.s);

}


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

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

}

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

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

}

// match user input to a possible response
cond {

    ([],[please,say,something]) ^                                   :- true;
    ([bye],[goodbye]) ^                                             :- true;
    ([you,feel|:x],[i,sometime,feel,the,same,way]) ^                :- true;
    ([because|:x],[is,that,really,the,reason]) ^                    :- true;
    ([you,have|:x],[how,long,have,you,had,:x]) ^                    :- true;
    ([yes|:x],[how,can,you,be,so,sure,:x]) ^                        :- true;
    ([me,are|:x],[oh,yeah,i,am,:x]) ^                               :- true;
    ([do,me,think|:x],[i,think,you,should,answer,that,yourself]) ^  :- true;

    ([you,are,:x],:o)                       :- #wword(:w), lst.cat([please,tell,me],:w,[you,are],:x,:o), true ^;
    ([:v,:x],[why,do,you,want.me,to,:v,:x]) :- #verbp(:v), true ^;
    ([:w,:x],[you,tell,me,:w])              :- #wpred(:w), true ^;
    ([:w,me,:x],[perhaps,i,:w,:x])          :- #wpred(:w), true ^;

    (:i,[for,dream,analysis,see,freud]) :- lst.member(dream,:i), true ^;
    (:i,[all,is,fair,in,love,and,war])  :- lst.member(love,:i), true ^;
    (:i,[dont,be,so,negative])          :- lst.member(no,:i), true ^;
    (:i,[be,more,decisive])             :- lst.member(maybe,:i), true ^;
    (_,:o)                              :- #punts(:o);

}

// main 'function'
shrink {

    (:i)    :- #s2ls(:i,:l), #you.me.map(:l,:l2), #cond(:l2,:o), lst.cat(:o,:o2), str.tokenize(:s," ",:o2), console.puts(:s);
    (:i,:s) :- #s2ls(:i,:l), #you.me.map(:l,:l2), #cond(:l2,:o), lst.cat(:o,:o2), str.tokenize(:s," ",:o2);

}

// prompt
shrink.prompt {

    ()           :- console.puts("Hello, what's up?"), &console.gets(:i), #shrink(:i,:o), console.puts(:o),
                    #shrink.prompt(:o);
    ("goodbye")^ :- true;
    (_)          :- &console.gets(:i), #shrink(:i,:o), console.puts(:o), #shrink.prompt(:o);

}

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

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