From UBC Wiki

Authors: Owain, Han, Gabriel

What is the problem?

Our goal is to design a chatbot using Prolog which allows users to look for job postings, and has the ability to measure their qualification based on their inputted resume. We hope to score users based on their skill set and job requirements to determine if they will be a good fit for the position they are applying for.

What is the something extra?

We will be implementing a variety of features to fully illustrate the HR-domain by looking for keywords and phrases in the user's responses to determine their score. for full details

  • Users can query against a knowledge base of encoded Job Postings
  • Users can dynamically create, view, modify, and save their Resume on the fly
  • Users may measure their Resume against Job Postings and have it be scored, diffed, and analyzed based on their qualifications
  • Users can search up definitions through Http against a dictionary API
  • A Text-based GUI

What did we learn from doing this?

Here we discuss our insights, grievances, and overall impressions on our journey throughout this project.

Application Implementation

Prolog was definitely suitable for the task. Building an app bottom-up required us to rework how our brains worked quite a bit, though it was a refreshingly pleasant way of managing the structure. Though hard to describe in words, It felt like we had to trust in the result of our helper functions more due to the truthy nature of the language and felt more modular in a sense as a result. Comparing it to Haskell, there are definitely a lot of similarities in terms of grievances. To name a few, the lack of polymorphism and the need for getter functions gives us much more appreciation to the quality of life found in the usual imperative languages. For instance, sometimes I felt I wanted to use a function pointer or Java's polymorphism to customize print statements easier rather than creating separate functions. One particular nuance introduced when we were coding in Prolog was the idea of control flow. Usually, we can decide multiple exit points in our languages such as a simple if-statement to proceed to a next function or return value. However, Prolog required us to often add an intermediary function to replicate this behavior. At times, this can feel tedious to supplement on our part as conditional branching is such a fundamental tool for a programmer. Again, we dread the idea of scaling up an application as these annoyances can only be compounded as it grows.

Knowledge Base Encoding

Encoding properties of our knowledge base felt very different from the usual tasks in other languages we deal with. To make a comparison, we were both the client interacting with the database, and the database itself. The properties themselves felt like we were making explicit object instantiations and required the workload one would expect when filling up a database with values. Assert and retract had parallels to insert and delete but without the structure and support one would get from a fully-fledged database system. For instance, by default we are capable of asserting duplicate facts in Prolog whereas in a database system, this would likely not occur when constraints are properly set up. On our end, we had to first remove the old fact(s), then add the new one in order to replicate an update functionality. As well, using a database would handle these values being persisted after the session while Prolog would again, require the user to implement the feature. Despite this, the experience as a whole was pleasant enough though as this style of bridging application functionality and database values directly was a unique adventure for the members in our group.


Value Processing

One area of hassle we didn't expect was the modification of user input. Input/Output is essential in an interactive application such as ours and it's important that we can correctly parse the values into our functions. In our case, we found that it was very difficult to to modify our user input to be encapsulated in quotes to avoid reliance on the user to type them. A very basic problem of converting the input to a string took us an unexpected amount of effort to resolve whereas this was almost never an issue in the languages we usually work with. SWI-Prolog does not have a quick way to covert input or values into strings (such as simply doing "" + intVar + ""), and the suggestions on swi-prolog docs were not the most helpful to understand. Another example is modifying our print statements strings (such as doing $"some {intVar} here" in another language) took a bit more lines to work due to this conversion issue and is also partially made worse with the control flow limitations. We are reminded again when encountering these problems that documentation, common problems, and FAQs as a whole can sometimes be scarce for languages like Haskell and Prolog. At times it may even feel insufficiently detailed as the SWI-Prolog documentation often doesn't specify sample values for the function arguments (ex. the int values for a key_mode) as an example. These weak points again, may server another possible deterrent to adopting these languages in our personal use beyond the scope of this course.


Word Dictionary Functionality

Implementing the ability for users to look up definitions of words to help them search for jobs was a challenging "something extra" for us to tackle. We decided to use Merriam-Webster's Collegiate Dictionary API to give users access to virtually any definition they desire. One challenge was processing the user's input to correctly match the API's requirements so that we could first pull information from the dictionary. Specifically, formatting the request URL properly. The main challenges we faced with this implementation were reading the JSON that was returned by the API, which contained a ton of extra information that was not directly related to the word's definition. Navigating the response required us to incrementally breakdown the result until we could get it into a structure we were comfortable with. In contrast to our past exposure to response formats, it required a lot more helper functions to call on the term with a specific type. For instance, we needed convert it to a dict, then call is_dict(Term) and get_dict(Term) whereas in other languages its as easy as doing json.key1.key2.key3 to get the values. However, the code to setup the HTTP was relatively short with it being one call to http_get(). Granted, we needed to understand how it all works in the first place.



Overall, functional programming was suitable to complete our task to create a chatbot. Each functionality of the chatbot can be written in separate functions and called by our main function. We are happy with the final product we created and feel it is pretty thorough as a standalone application. Some highlights include: figuring out how to implement various quality of life features (such as removing the tedium of a period for input), recreating a dictionary's key counting implementation, integrating an API through Http requests, supporting dynamic modification of our database, and implementing file writing to save information.


Links to code etc