Search code examples
prolog

Prolog DCG capture two element list in one rule, and strings to list conversion


move(Move) --> ["move", Move], { format("__ ~w", Move) }.
moves(Moves) --> ["moves"], Moves, { length(Moves, 2), format("__ ~w", Moves) }.


% this works as expected.
hello :- split_string("move ten", " ", "", Ls), phrase(move(_), Ls).

% this throws arguments error, I want to capture the list [one, two, three].
hello2 :- split_string("moves one two three", " ", "", Ls), phrase(moves(_), Ls).


% finally I want this to work without split_string debacle.
hello3 :- phrase(move(_), "move ten").


% note that it also has to work from strings read from stdin.

hello4 :- 
read_line_to_string(user_input, L), 
phrase(move(_), L).

% And no this line had no effect:
:- set_prolog_flag(double_quotes, chars).

Solution

  • How about:

    % Show lists of codes nicely
    :- portray_text(true).
    
    moves([Move]) --> "move ", alnums(Move).
    moves(Moves) --> "moves ", moves_list(Moves).
    
    moves_list([Move|Moves]) --> alnums(Move), " ", moves_list(Moves).
    moves_list([Move]) --> alnums(Move).
    
    alnums([C|Cs]) --> alnum(C), alnums(Cs).
    alnums([C]) --> alnum(C).
    
    alnum(Digit) --> [Digit], { between(0'0, 0'9, Digit) }.
    alnum(Lower) --> [Lower], { between(0'a, 0'z, Lower) }.
    alnum(Upper) --> [Upper], { between(0'A, 0'Z, Upper) }.
    

    Results in swi-prolog:

    ?- M = `move one`, once(phrase(moves(L), M)).
    L = [`one`].
    
    ?- M = `moves one`, once(phrase(moves(L), M)).
    L = [`one`].
    
    ?- M = `moves one two three`, once(phrase(moves(L), M)).
    L = [`one`,`two`,`three`].