78
submitted 3 days ago* (last edited 3 days ago) by sebastiancarlos@lemmy.sdf.org to c/programmerhumor@lemmy.ml

The mystery is finally solved! Yes, the code works.

#!/usr/bin/env swipl --quiet

:- 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).

you are viewing a single comment's thread
view the rest of the comments
[-] AnarchistArtificer@slrpnk.net 11 points 3 days ago

Incredible. I don't know enough Prolog to be able to follow it very well, but this is truly what the internet was made for

this post was submitted on 07 Jan 2025
78 points (97.6% liked)

Programmer Humor

32707 readers
163 users here now

Post funny things about programming here! (Or just rant about your favourite programming language.)

Rules:

founded 5 years ago
MODERATORS