RabbitFarm

2025-04-06

The Weekly Challenge 315 (Prolog Solutions)

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

Part 1: Find Words

You are given a list of words and a character. Write a script to return the index of word in the list where you find the given character.

This can be done with a basic predicate with findall. Or we can use maplist! maplist is more fun in my opinion, so we’ll go with that.

First off a small utility predicate to see if a word contains a given letter.

contains letter 1 ⟩≡


contains_letter(Letter, Index-Word, Index):-
atom_chars(Word, C),
member(Letter, C).
contains_letter(_, _, -1).

Fragment referenced in 4.

You can see that we are sending that previous predicate a pair. The first element in that pair is an index. Let’s build a word index, mainly for the sake of avoiding the use of between and findall. Those builtin predicates are fine, but aesthetically to me it seems nicer to not use them if we absolutely don’t have to.

build word index 2 ⟩≡


word_index(Words, Index):-
word_index(Words, 0, Index).
word_index([], _, []).
word_index([H|T], N, [I-H|Index]):-
succ(N, I),
word_index(T, I, Index).

Fragment referenced in 4.

Now we’ll use maplist to find the words.

find the indices of words that contain the letter 3 ⟩≡


find_words(Words, Letter, Indices):-
word_index(Words, Index),
maplist(contains_letter(Letter), Index, I),
delete(I, -1, Indices).

Fragment referenced in 4.

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

"ch-1.p" 4


contains letter 1
build word index 2
find the indices of words that contain the letter 3

Sample Run
$ gprolog --consult-file prolog/ch-1.p 
| ?- find_words([the, weekly, challenge], e, Indices). 
 
Indices = [1,2,3] ? 
 
yes 
| ?- find_words([perl, raku, python], p, Indices). 
 
Indices = [1,3] ? 
 
yes 
| ?- find_words([abc, def, bbb, bcd], b, Indices). 
 
Indices = [1,3,4] ? 
 
yes 
| ?-
    

Part 2: Find Third

You are given a sentence and two words. Write a script to return all words in the given sentence that appear in sequence to the given two words.

In the first part I mentioned the between and findall predicates. Here we will use them to find successive words.

find third 5 ⟩≡


find_third(Words, One, Two, Thirds):-
length(Words, WordLength),
N is WordLength - 2,
findall(Third, (
between(1, N, I),
succ(I, J),
nth(I, Words, One),
nth(J, Words, Two),
succ(J, K),
nth(K, Words, Third)
), Thirds).

Fragment referenced in 6.

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

"ch-2.p" 6


find third 5

Sample Run
$ gprolog --consult-file prolog/ch-2.p 
| ?- find_third([’Perl’, is, a, my, favourite, language, but, ’Python’, is, my, favourite, too], my, favourite, Thirds). 
 
Thirds = [language,too] 
 
yes 
| ?- find_third([’Barbie’, is, a, beautiful, doll, also, also, a, beautiful, princess], a, beautiful, Thirds). 
 
Thirds = [doll,princess] 
 
yes 
| ?- find_third([we, will, we, will, rock, you, rock, you], we, will, Thirds). 
 
Thirds = [we,rock] 
 
yes 
| ?-
    

References

The Weekly Challenge 315
Generated Code

posted at: 17:41 by: Adam Russell | path: /prolog | permanent link to this entry