1

I've been trying to write a simple web service in Prolog and was wondering how I can handle optional parameters. I thought that with library(http/http_parameters) it may be as simple as that:

my_request_handler(Request) :-
    http_parameters(Request, [ param_1(Param1, []), param_2(Param2, []) ]),
    ... ### handle both parameters

my_request_handler(Request) :-
    http_parameters(Request, [ param_1(Param1, []) ]),
    ... ### handle only param_1

so if param_2 is not provided the engine will backtrack to the second rule. But in SWI-Prolog http_parameters raises exception if parameters do not match the specification and so the code breaks on the first rule rather than trying to evaluate the second one.

Unfortunately, adding optional(true) to the param_2 specification makes it unbound and forces me to use a conditional check like this:

my_request_handler(Request) :-
    http_parameters(Request, [ param_1(Param1, []), param_2(Param2, [optional(true)]) ]),
    (error:text(Param2) ->
       ... ### handle both parameters
    ;
       ... ### handle only param_1
    ).

Is this the best way of doing things or I am missing something? I guess, that the conditionals become much uglier if more than one parameter is optional...

Cheers,

Jacek
  • 1,048
  • 15
  • 21

1 Answers1

2

Summary

There are at least two ways out:

  1. You can combine optional/1 with default/1, and specify a value that can otherwise not occur.

  2. You can specify list/1 to obtain a list, and use pattern matching to distinguish the cases.

See below for more details.

Using default/1

For example, to implement option 1, you could write:

my_request_handler(Request) :-
        http_parameters(Request, [ param_1(Param1, []),
                                   param_2(Param2, [optional(true),
                                                    default(none)])
                                 ]),
        handle_parameters_(Param1, Param2).

and distinguish the cases with if_3:

handle_parameters_(Param1, Param2) :-
        if_(Param2 = none,
            Then,
            Else).

Main drawback: To really distinguish the cases by pattern matching, you would have to convert this to a clean representation. Without this, you also risk that one of the attributes legitimately overlaps with the value you are using to mean "not specified". One suitable representation could look like this:

  • none for "not specified"
  • atom(A) for the atom A.

However, this conversion again requires that you manually implement the distinction, using for example var/1 in the example you posted.

Using list/1

Option (2) is somewhat less error-prone, albeit slightly more indirect.

You can apply it like this:

my_request_handler(Request) :-
        http_parameters(Request, [ param_1(Param1, []),
                                   param_2(Param2, [list(atom)])
                                 ]),
        handle_parameters_(Param1, Param2).

Then, you can distinguish the cases by pattern matching:

handle_parameters_(Param1, []) :-
        ...
handle_parameters_(Param1, [Param2]) :-
        ...

This seems quite OK to me.

Community
  • 1
  • 1
mat
  • 40,498
  • 3
  • 51
  • 78