Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / F#

Eliza like chat bot in F# language for fun

4.33/5 (2 votes)
8 Jul 2010CPOL4 min read 33.2K   515  
Eliza like chat bot in F# for having fun learning the functional programming language shipped with Visual Studio 2010.

Sample chat bot applicaction.

Introduction

This is a very simple Eliza like chat bot. I call it Meliza Sharp. I wrote it for having fun learning the F# language shipped with Visual Studio 2010. There are some very good implementations of the Eliza chat bot written in LISP out there, in case you want to make your own chat bot. Search for it.

Meliza Thinking Code

The Meliza algorithm is based upon rules and pattern matching. And this is one of the powerful features of F#.

The following function defines the Pattern Identifiers: Wish, Positive, Negative, and None, and also when an input string will match these pattern identifiers.

If the input string matches with "want", "desire", or "need", then input will match with the Wish pattern identifier.

If the input string matches with "certainly", "yes", "ok", or "right", then input will match with the Positive pattern identifier. And so on with the rest of the pattern identifiers.

This is what F# developers call active recognizers. Active recognizers act as sort of discriminators that will divide the input in different categories, in this case, in to different 'subjects' of conversation.

fsharp
// Define an active recognizer for keywords
// that express desire, positive and negative statements.
let (|Wish|Positive|Negative|None|) input =
    match input with
        | "want" | "desire" | "need"
                -> Wish
        | "certainly" | "yes" | "true" | "ok" | "right"
                -> Positive
        | "not" | "no" | "don't" | "false" | "wrong"
                -> Negative
        | _ -> None

In this other function, the exception handling try ... with construction acts as a conditional. A match of the input string with the pattern identifier Number will be possible only if the conversion Convert.ToDouble(input) succeeds.

fsharp
// Define an active recognizer for numbers
// If the conversion suceeds it is a Number
// else it is None
let (|Number|None|) (input:string) =
    try let value = Convert.ToDouble(input) 
        Number
    with 
       | _ -> None

Once all the active recognizers we want for matching the string tokens are defined, we create the recursive response function which takes the first token of the string and the rest of it as parameters.

We search for a match with token and the active recognizers defined above. That is, we find in which defined category or 'subject' the token falls into.

If we find the token falls into one of the predefined categories, then we return the response for that category by calling the corresponding function response. And this will end the recursive process.

If a match is found with | None when (str.IndexOf(" ") > 0), we recursively pass the next token and the rest of the string to the response function. That is, we haven't found a category for the current token, and there is still more tokens in the string, so we call the response function with the next token and the remaining string str, to be processed recursively.

If a match is found with | None when (str.IndexOf(" ") < 0) , that is, we haven't found a category for the current token, and there is no more tokens in the string, we call the response function with the next token and the remaining string empty.

The when statement sets a guard or condition to restrict the possible matches of token with None.

fsharp
// main recursive response function
// find the first match with a key token
// and return a response acordingly 
let rec response (token: string) (str: string) =
   match token with
     | Hello
            -> hello_response ()
     | Bye
            -> good_bye_response ()
     | Personal
            -> personal_response str
     | Question
            -> question_response str
     | Answer
            -> answer_response str
     | Wish 
            -> wish_response str
     | Negative 
            -> negative_response str
     | Positive 
            -> positive_response str
     | Math
            -> math_response str
     | "" 
            -> none_response str
     | None when (str.IndexOf(" ") > 0) 
            -> response (str.Substring(0,str.IndexOf(" "))) 
                        (str.Substring(str.IndexOf(" ")+1))
     | None when (str.IndexOf(" ") < 0) 
            -> response str ""
     | None 
            -> math_response str

Finally, we create a set of functions which randomly select the responses on the 'subject' recognized by the response function and the active patterns.

Here are two of them:

fsharp
// Select possible responses based on random number for hello 'subject'
let hello_response () =
    let n = rand.Next(10) 
    match n with
        | 0 -> "How do you do."
        | 1 -> "Is nice talking to you."
        | 2 -> "Tell me something new."
        | 3 -> "Nice to meet you."
        | 4 -> "My pleasure."
        | 5 -> "Hi."
        | 6 -> "Hello."
        | 7 -> "Good day."
        | 8 -> "Salutation!"
        | 9 -> "Welcome!"

// Select possible responses based on random number for Good bye 'subject'
let good_bye_response () =
    let n = rand.Next(10) 
    match n with
        | 0 -> "Talk to you soon."
        | 1 -> "It was nice talking to you."
        | 2 -> "Good bye."
        | 3 -> "Stay a bit longer."
        | 4 -> "Adios amigo."
        | 5 -> "Bye."
        | 6 -> "Adios."
        | 7 -> "See you."
        | 8 -> "Please don't go"
        | 9 -> "Why are you leaving me alone?"

How to Create the Visual F# Application and the Windows Form

  1. File -> New -> Project

    Create a New Eliza Visual F# Application.

Add the Windows Components References:

  1. In Solution Explorer, right cick References -> Add Reference...
  2. Click on the .NET tab and select System.Drawing and System.Windows.Form from the list.
  3. Click the OK button.

Design the Form

There is no form designer within Visual Studio for F#, so what I recommend is to use the designer for another .NET language like VB.NET.

  1. Close the solution, or open another instance of Visual Studio.
  2. File -> New -> Project

    Create a New Temporal Visual Basic, Windows Forms Application.

  3. Drag a TextBox from the Toolbox into the form.
  4. Right click the TextBox within the form -> Properties.
  5. Set the Name property to text_box.
  6. Set the Dock property to Bottom.
  7. Drag another TextBox from the Toolbox into the form.
  8. Right click the TextBox within the form -> Properties.
  9. Set the Name property to conversation_box.
  10. Set the Dock property to Fill.
  11. Set the Multiline property to True.
  12. Save the Temporal project.

Translate the code into F#:

  1. Open the Eliza project.
  2. Go to File -> Open -> File...
  3. Browse to the Projects folders, Temporal project, open the Form1.Designer.vb file.
  4. Browse to Private Sub InitializeComponent(); in Form1.Designer.vb, there are the properties we must set for our form.

Add the code for the function to create our form:

// Create a main form, you can create a form using
// the form designer, in another language like Vb .Net
// then open the file Form1.Designer.vb and voila!
// there is the code you can translate into F#
let main_form title =
  // text box
  let text_box = new TextBox()
  text_box.Dock <- DockStyle.Bottom 
  // conversation box
  let conversation_text = new TextBox()
  conversation_text.Dock <- DockStyle.Fill
  conversation_text.Multiline <- true
  conversation_text.WordWrap <- false
  conversation_text.Font <- new Font(string("Arial"),float32(10))
  conversation_text.ReadOnly <- true
  // main form
  let form = new Form(Text=title, Visible=true)
  form.Size <- new Size(512, 512)
  form.Controls.Add(conversation_text)
  form.Controls.Add(text_box)
  // Message handler for Key Down event
  text_box.KeyDown.Add(enter_message text_box conversation_text)
  //
  let gotfocus = text_box.Focus()
  //
  form.KeyDown.Add(fun e -> if e.KeyCode = Keys.Escape then form.Close());
  form

Build and run the application.

  1. Open the Eliza project.
  2. Go to Project -> Eliza Properties...
  3. In the Application tab, set Output type to Windows Applications.
  4. Press the F5 Key ;-)

Points of Interest

That's it!

History

Just posted.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)