Search code examples
prologdcg

How to write optional in SWI-Prolog


I need to implement some rules by Prolog

ex:

S ---> A,[b],{c}.

Where:

[b] could happen once or none like 0 or 1 time

{c} could happen 0,1,2,...times

How can i write it?

Edit:

I used this:

:- op(700,xfx,--->).
s ---> [vp].
s ---> [vp,conj,vp].
s ---> [vp,conj,np].
vp ---> [feal_amr],
        ([mfoal_beh];[]),
        ([mfoal_beh];[]),
        ([bdl];[]),
        [sefa_optional],
        ([hal];[]),
        ([shbh_gomla];[]),
        ([mfoal_motlk];[]).

It gives me an error "Full stop in clause-body? Cannot redefine ,/2"

in the comma in this line "vp ---> [feal_amr], ..."

Edit

I use "--->" because i have this

parse_topdown(Category,String,Reststring,[Category|Subtrees]) :-
        Category ---> RHS,
        matches(RHS,String,Reststring,Subtrees).

And "-->" gives an error with the operator ":-"?!!

this is my code for an Arabic Parser Code

I'm sorry for inconvenience but i am not an expert in Prolog


Solution

  • from your description

    s --> [a], ([b] ; []), c_1.
    c_1 --> [c], c_1 ; [].
    

    some test pattern:

    ?- phrase(s, [a,b,c,c,c]).
    true
    
    ?- phrase(s, [a]).
    true
    

    edit

    about your code: you should use -->. Why you declare ---> (and not define it) ? That way you should write your own analyzer, you're not using DCG.

    Note that [vp,conj,vp] it's a list of terminals,

    Not sure about feal_amr,mfoal_beh, etc etc, but vp it's surely a nonterminal (it's rewritten).

    Then I think you should write

    s --> vp.
    s --> vp,conj,vp.
    s --> vp,conj,np.
    
    vp -->
      [feal_amr],
      ([mfoal_beh];[]),
      ([mfoal_beh];[]),
      ([bdl];[]),
      [sefa_optional],
      ([hal];[]),
      ([shbh_gomla];[]),
      ([mfoal_motlk];[]).
    
    % I hypotesize it's a comma.
    conj --> [','].
    

    edit as noted in comments, you are not using DCG, but your own interpreter. I tested it with a minimal example

    :- op(700,xfx,--->).
    
    s ---> [name,verb,names].
    
    names ---> [name, conj, names].
    names ---> [name].
    names ---> [].
    
    lex(anne, name).
    lex(bob, name).
    lex(charlie, name).
    
    lex(call, verb).
    lex(and, conj).
    
    parse_topdown(Category,[Word|Reststring],Reststring,[Category,Word]) :-
            lex(Word,Category).
    
    parse_topdown(Category,String,Reststring,[Category|Subtrees]) :-
            Category ---> RHS,
            matches(RHS,String,Reststring,Subtrees).
    
    matches([],String,String,[]).
    matches([Category|Categories],String,RestString,[Subtree|Subtrees]) :-
            parse_topdown(Category,String,String1,Subtree),
            matches(Categories,String1,RestString,Subtrees).
    

    and this program accepts 0,1, or more names:

    ?- parse_topdown(s,[anne,call,bob,and,charlie],R,P).
    R = [],
    P = [s, [name, anne], [verb, call], [names, [name, bob], [conj, and], [names|...]]] ;
    R = [charlie],
    P = [s, [name, anne], [verb, call], [names, [name, bob], [conj, and], [names]]] ;
    R = [and, charlie],
    P = [s, [name, anne], [verb, call], [names, [name, bob]]] ;
    R = [bob, and, charlie],
    P = [s, [name, anne], [verb, call], [names]] ;
    false.
    

    Note I leave R free, to examine partial matches. Coming back to your original question, you can see how the nonterminal names accepts 0,1,or many (separed by and) values.

    Note that such interpreter will be very slow on any substantial input. I'd advise you to rewrite your grammar using DCG.