Course:CPSC312-2021/NLI

From UBC Wiki

Lyric Generation

Authors: Edward Chang, Sheetal Shajan, Yichen Xin

What is the problem?

We want to implement a prolog program that can generate semi-random lyrics / poems. The poems / lyrics generated have details that are specified by the user at the beginning of the program. These details are the number of lines in the poem, the number of words in each line, the mood of the poem and the presence of rhyming in the poem.

Reference : Pieces of our project are based on / inspired by Chomsky Sentence Generator, with permission granted. Thank you to Joshua!

What is the something extra?

We wanted to take an advanced detail of lyrics and poetry and see if we could incorporate into our generator. We chose to add rhyming to our generator. We also added mood to our generator.

What did we learn from doing this?

In many cases, especially in those where we need to define some sort of structure/rule, Prolog was very effective. For example, for generating individual lines in the poem, we generated the lines word by word with a fixed structure, an idea that was inspired by the Chomsky Sentence Generator. The functions for generating these lines were extremely intuitive to write due to prolog's syntax, as the word by word structure of the line is the first parameter of the predicate, so it can easily be seen/understood what the structure was, and extended upon. Once we had one line type defined, it was easy to extend the code to have more sentence types. In addition, it was very intuitive to write code to cover different cases. For example, if a user wanted a certain topic, or a set amount of words per line, we just needed to define multiple versions of a predicate, where there is a set atom or number that matches the case. This "pattern matching" functionality, which was also present in Haskell, makes the code very clean / readable and extendible.


Prolog was more tricky in writing and debugging more complicated algorithms. For example, our program has a recursive algorithm for determining when a line should rhyme with the previous line. Because Prolog is not like other languages where there is a set return value, and instead it can generate an arbitrary amount of answers, there were several problems where there were more answers than expected, or even no answers. I also found it difficult to debug using SWI-Prolog / Trace, as Prolog parses code with a back-tracking algorithm, instead of going intuitively going line-by-line, and not re-trying, like an imperative language. In my opinion, it is much easier to imperatively tell a program how to do an algorithm, rather than trying to figure out a logical statement where your desired return value would make it true.  We also attempted adding topic to our lyric generator and ran into a stack overflow error. Upon using trace to debug this issue, we found that it was stuck in an infinite loop of calling the list of nouns defined for topic and list of nouns defined for a generic topic. We decided that topic would not contribute much functionality to our code since we already have mood, which is quite similar, and due to our previous issues with debugging, we did not include it. Overall however, we learned that Prolog was suitable for this task.


Here is an example of the output of our lyric generator:

tame the artistically fuzzy goal

lovely brain kills corageously throughout soul

tame the artistically dreamy heart

dreamy heart loves deeply into art

Links to code etc

https://github.com/PythonSyntax1/Lyric-Generator