Last active
January 8, 2025 03:40
-
-
Save sebastiancarlos/3ed44d4f14410d4a1825296427204478 to your computer and use it in GitHub Desktop.
Blur's "Girls and Boys" lyrics generator in Prolog
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env swipl --quiet | |
% All my gist code is licensed under the MIT license. | |
:- use_module(library(clpfd)). | |
% ORIGINAL LYRICS: | |
% Looking for | |
% Girls who want boys | |
% Who like boys to be girls | |
% Who do boys like they're girls | |
% Who do girls like they're boys | |
% Always should be someone you really love | |
% - "Girls and Boys," Blur, 1994 | |
% DSL CONVERSION: | |
% girls who like boys | |
% who like boys (who are girls) | |
% who like boys (who get done like they're girls) | |
% who like girls (who get done like they're boys) | |
% TREE STRUCTURE: | |
% group(female, none, none, group( | |
% male, female, none, group( | |
% male, none, female, group( | |
% female, none, male, none)))). | |
% USAGE: | |
% 1. Get all possible lyrics up to a max depth: | |
% ?- group_maxdepth(G, 4), group_string(G, S). | |
% 2. Get the tree structure of some lyrics (pass a max depth to avoid unbounded recursion): | |
% ?- group_maxdepth(G, 4), group_string(G, 'boys who like girls'). | |
% 3. Get the lyrics from a tree structure: | |
% ?- group_string(group(male, none, none, group(female, none, none, none)), S). | |
% 4. Fill in the blanks with all possibilities: | |
% ?- group_depth(G, 3), | |
% phrase(group_sentence(G), Tokens), | |
% append([[girls, who, like], X, [who, like], Y], Tokens), | |
% atomic_list_concat(Tokens, ' ', S). | |
% Genders | |
gender(male). | |
gender(female). | |
% gender_altgender(G, G2) | |
% Valid relation between gender and alternative genders (isGender and | |
% PerformGender) in the same group. | |
gender_altgender(G, none) :- | |
gender(G). | |
gender_altgender(G, G2) :- | |
gender(G), | |
gender(G2), | |
dif(G, G2). | |
% Group(Gender, IsGender, PerformGender, LikeGroup). | |
% All arguments but Gender are optional. | |
% Represents a demographic that can like and can be a target of liking. | |
group(Gender, IsGender, PerformGender, none) :- | |
gender(Gender), | |
gender_altgender(Gender, IsGender), | |
gender_altgender(Gender, PerformGender). | |
group(Gender, IsGender, PerformGender, group(Gender2, IsGender2, PerformGender2, Group)) :- | |
group(Gender, IsGender, PerformGender, none), | |
group(Gender2, IsGender2, PerformGender2, Group). | |
% DCG to produce a phrase from a group. | |
% Example: | |
% ?- phrase(group_sentence(group(male, none, none, group(female, none, none, group(male, none, none, group(male))))), Tokens). | |
% Tokens = [boys, who, like, girls, who, like, boys, who, like, boys]. | |
group_sentence(group(Gender, IsGender, PerformGender, none)) --> | |
{ group(Gender, IsGender, PerformGender, none) }, | |
gender_phrase(Gender), | |
group_info_phrase(IsGender, PerformGender). | |
group_sentence(group(Gender, IsGender, PerformGender, Group)) --> | |
{ dif(Group, none) }, | |
group_sentence(group(Gender, IsGender, PerformGender, none)), | |
[who, like], | |
group_sentence(Group). | |
gender_phrase(male) --> [boys]. | |
gender_phrase(female) --> [girls]. | |
isgender_phrase(none) --> []. | |
isgender_phrase(Gender) --> [are], gender_phrase(Gender). | |
performgender_phrase(none) --> []. | |
performgender_phrase(Gender) --> [get, done, like, 'they''re'], gender_phrase(Gender). | |
% Render isGender and PerformGender within parentheses. | |
group_info_phrase(none, none) --> []. | |
group_info_phrase(IsGender, none) --> | |
{ dif(IsGender, none) }, | |
['(', who], isgender_phrase(IsGender), [')']. | |
group_info_phrase(none, PerformGender) --> | |
{ dif(PerformGender, none) }, | |
['(', who], performgender_phrase(PerformGender), [')']. | |
group_info_phrase(IsGender, PerformGender) --> | |
{ dif(IsGender, none), dif(PerformGender, none) }, | |
['(', who], isgender_phrase(IsGender), ['and'], performgender_phrase(PerformGender), [')']. | |
% Relate group and string representation | |
% ?- group_string(group(male, none, none, group(female, none, none, group(male, none, none, group(male)))), S). | |
% S = 'boys who like girls who like boys who like boys' | |
group_string(group(Gender, IsGender, PerformGender, Group), String) :- | |
phrase(group_sentence(group(Gender, IsGender, PerformGender, Group)), Tokens), | |
atomic_list_concat(Tokens, ' ', String). | |
% Relate group and depth | |
% - group(G0, IG, PG, none) has depth 0 | |
% - group(G0, IG, PG, group(...)) has depth 1 | |
group_depth(group(Gender, IsGender, PerformGender, none), 0) :- | |
group(Gender, IsGender, PerformGender, none). | |
group_depth(group(Gender, IsGender, PerformGender, Group), Depth) :- | |
Depth #> 0, | |
group(Gender, IsGender, PerformGender, none), | |
Depth0 #= Depth - 1, | |
group_depth(Group, Depth0). | |
% Relate group and all integers larger than its depth. | |
group_maxdepth(Group, MaxDepth) :- | |
MaxDepth #>= Depth, | |
Depth #>= 0, | |
group_depth(Group, Depth). |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment