RabbitFarm

2025-03-09

The Weekly Challenge 311 (Prolog Solutions)

The examples used here are from the weekly challenge problem statement and demonstrate the working solution.

Part 1: Upper Lower

You are given a string consists of english letters only. Write a script to convert lower case to upper and upper case to lower in the given string.

GNU Prolog defines a predicate lower_upper/2 which does pretty much what this problem is asking for. We could also just use the character code values instead of chars, but using chars seems a little more elegant as it avoids ASCII math.

upper lower 1 ⟩≡


upper_lower(S, UpperLower):-
atom_chars(S, C),
upper_lower(C, UL, _),
atom_chars(UpperLower, UL).
upper_lower([], [], _).
upper_lower([C|T], [L|UL], _):-
lower_upper(C, C0),
C == C0,
lower_upper(L, C),
upper_lower(T, UL, _).
upper_lower([C|T], [U|UL], _):-
lower_upper(C, U),
\+ C == U,
upper_lower(T, UL, _).

Fragment referenced in 2.

The rest of the code just wraps this predicate into a file.

"ch-1.p" 2


upper lower 1

Sample Run
$ gprolog --consult-file prolog/ch-1.p 
| ?- upper_lower(’pERl’, UpperLower). 
 
UpperLower = ’PerL’ ? 
 
yes 
| ?- upper_lower(’rakU’, UpperLower). 
 
UpperLower = ’RAKu’ ? 
 
yes 
| ?- upper_lower(’PyThOn’, UpperLower). 
 
UpperLower = pYtHoN ? 
 
yes 
| ?-
    

Part 2: Group Digit Sum

You are given a string, $str, made up of digits, and an integer, $int, which is less than the length of the given string. Write a script to divide the given string into consecutive groups of size $int (plus one for leftovers if any). Then sum the digits of each group, and concatenate all group sums to create a new string. If the length of the new string is less than or equal to the given integer then return the new string, otherwise continue the process.

To solve this problem we need to do the following

  1. divide the list into groups of the given size
  2. compute the sums
  3. recombine
  4. repeat as needed

Let’s look at each of those pieces individually and then combine them together into one predicate.

divide the list into groups of the given size 3 ⟩≡


group_list(S, Size, GroupedList):-
atom_chars(S, C),
maplist(char_number, C, N),
group_list(N, Size, [], [], GroupedList).
group_list([], _, Group, GroupedListAccum, GroupedList):-
length(Group, L),
((L > 0, append(GroupedListAccum, [Group], GroupedList));
(GroupedList = GroupedListAccum)).
group_list([H|T], Size, Group, GroupedListAccum, GroupedList):-
length(Group, L),
L < Size,
append(Group, [H], G),
GLA = GroupedListAccum,
group_list(T, Size, G, GLA, GroupedList).
group_list([H|T], Size, Group, GroupedListAccum, GroupedList):-
length(Group, L),
L == Size,
append(GroupedListAccum, [Group], GLA),
group_list([H|T], Size, [], GLA, GroupedList).

Fragment referenced in 9.

Uses: GroupedList 8, Size 8.

turn a numeral into a number 4 ⟩≡


char_number(C, N):-
number_chars(N, [C]).

Fragment referenced in 9.

We can compute the sums using the GNU Prolog builtin predicate sum_list/2.

compute the sums 5 ⟩≡


maplist(sum_list, GroupedList, Sums),

Fragment referenced in 8.

Defines: Sums 7.

Uses: GroupedList 8.

join a list of numbers into a single atom 6 ⟩≡


join([], ’’).
join([H|T], A):-
join(T, A0),
number_atom(H, A1),
atom_concat(A1, A0, A).

Fragment referenced in 9.

recombine and check if done 7 ⟩≡


flatten(Sums, SumsFlatted),
join(SumsFlatted, A),
atom_property(A, length(Length)),
((Length =< Size, GroupDigitSum = A, !);
(group_digit_sum(A, Size, GroupDigitSum), !)).

Fragment referenced in 8.

Uses: GroupDigitSum 8, Size 8, Sums 5.

the main predicate 8 ⟩≡


group_digit_sum(S, Size, GroupDigitSum):-
group_list(S, Size, GroupedList),
compute the sums 5
recombine and check if done 7

Fragment referenced in 9.

Defines: GroupDigitSum 7, GroupedList 3, 5, Size 3, 7.

Finally, let’s assemble our completed code into a single file.

"ch-2.p" 9


the main predicate 8
divide the list into groups of the given size 3
turn a numeral into a number 4
join a list of numbers into a single atom 6

Sample Run
$ gprolog prolog/ch-2.p 
| ?- group_digit_sum(’111122333’, 3, GroupDigitSum). 
 
GroupDigitSum = ’359’ 
 
yes 
| ?- group_digit_sum(’1222312’, 2, GroupDigitSum). 
 
GroupDigitSum = ’76’ 
 
yes 
| ?- group_digit_sum(’100012121001’, 4, GroupDigitSum). 
 
GroupDigitSum = ’162’ 
 
yes 
| ?-
    

References

The Weekly Challenge 311
Generated Code

posted at: 00:39 by: Adam Russell | path: /prolog | permanent link to this entry