Search code examples
listprolog

Prolog: how to check if a word is contained in a list


Let's say I have these rules:

rule([a,t,e],[8]).
rule([f,o,r],[4]).

I have to check if in a word (for example [f,o,r,t,r,e,s,s]) there is a word that is in the list of rules and if there is to remove that word and replace it with the number it represents.(so it becomes [4,t,r,e,s,s]).

Any ideas?


Solution

  • Assuming you want a single replacement:

    text_l33t(W, L33t) :-
       rule(A, B),
       phrase( ( seq(Pre), seq(A), seq(Post) ), W),
       phrase( ( seq(Pre), seq(B), seq(Post) ), L33t).
    
    seq([]) -->
       [].
    seq([E|Es]) -->
       [E],
       seq(Es).
    

    Alternatively, you could express that relation with append/3, but with even minimally more complex examples, append/3 will make things much more difficult to handle.

    Consider also to use the Prolog flag double_quotes as described in this answer because it permits you to use double quotes. You could then write rule("to","2"). rule("ight","ite"). and get back nice answer substitutions, like so:

    ?- text_l33t("right", L).
       L = "rite".
    

    If you want optionally more than one replacement, things become a bit more complex to specify. What about overlapping different rewrites? What about rewrites that get longer and longer? The following definition incorporates all possible rewrites:

    text_xl33t(W, W).
    text_xl33t(W, L33t) :-
       text_l33t(W, L0),
       text_xl33t(L0, L33t).
    

    What you probably want is a maximal rewrite. While you can write this down in Prolog, I would not do this as a beginner: You are leaving the pure monotonic part of Prolog for that.


    Edit: It seems you are still not happy with what I described. So here is text_maxl33t/2:

    text_maxl33t(W, L33t) :-
       text_xl33t(W, L33t),
       \+ text_l33t(L33t, _).
    

    Note that this predicate is still a relation. That is, for a single word you might have several independent maxl33ts since rewriting is not necessarily confluent.