"Default" clause first

Hi,

I have a case where multifile predicates’ “fallback” clauses are defined before other, more specific ones. In a nutshell, imagine a system where we predefined some predicates that work for default cases, but we need to be able to override them with dynamically loaded files.

I was at first thinking about some voodoo-level tinkering of being able to reverse the order of specified predicates, but then I came up with a slightly more explicit solution, and then I ended up with this extremely unportable answer:

more_alternatives(T) :-
  prolog_current_frame(F),
  prolog_frame_attribute(F, parent, F1),
  prolog_frame_attribute(F1, has_alternatives, T).

a(1) :-
  more_alternatives(false).

Querying:

?- a(X).
X = 1.

Loading this file:

a(2).

If we query this now:

?- a(X).
X = 2.

However, it has a serious drawback in that it disregards the fact that alternatives may not succeed due to their bodies, and therefore the predicate won’t succeed through this default clause in this case.

What’s a better solution to this (and perhaps something that doesn’t require a lot of tedious wrapping of every case where I need these defaults)?

Edited: I suppose it is better to leave it non-deterministic and try to find the “last” (more authoritative in my case) clause to use.

Does this suffice?

default(1).

:- dynamic data/1.
data(2).
data(3).

run :-
    (   data(X)
    *-> writeln(data),
        writeln(X)
    ;   default(X),
        writeln(default),
        writeln(X)
    ).  

Result:

?- run.
data
2
true ;
data
3
true.

Then, if the 2 data rows are commented out:

?- run.
default
1
true.
1 Like

I know the construct if-then-else in Prolog (… → … ; …), but I didn’t know the existence of this variety with the asterisk: (… *-> … ; …)
What’s the difference? Thanx

Explanation: *->/2

If it’s really necessary to use the same functor for the default, then could use:

run_same_name :-
    once(data(Default)),
    (   data(X),
        dif(X, Default)
    *-> writeln(data),
        writeln(X)
    ;   writeln(default),
        X = Default,
        writeln(X)
    ).
1 Like

Thank you, this is helpful, I got it down to:

setting(default).

%setting(1).
%setting(2).

get(X) :-
    once(setting(Default)),
    (   setting(X),
        dif(X, Default)
    *-> true
    ;   X = Default
    ).

I am now figuring out if I can generalize it to any predicate. Barring that, maybe I can write a meta-predicate to apply to these “setting” predicates.

Could use functor/3 to be able to specify the functor name.

1 Like

I think I got it working, thank you very much!

setting(default).

%setting(1).
%setting(2).

get(F) :-
    functor(F, _, Arity),
    arg(Arity, F, X),
    copy_term(F, F1),
    once(F1),
    arg(Arity, F1, Default),
    (   call(F),
        dif(X, Default)
    *-> true
    ;   X = Default
    ).

Do you think I can improve anything here?

(It bothers me a little bit that we call the same goal twice but filter out by dif; any way to improve on this?)

Why wouldn’t the arity simply be 1?

A better design would be for the default to have a different functor name, as per my first example.

In my case, the predicates with defaults most often have an arity different from 1 and may be of different arity. I have many such predicates and prefer not to have a different default predicate.

In a nutshell, imagine having a predicate object_property1(Obj, Prop), object_property2(Obj, Prop, Extra), etc. If I were to have, say, default(object_property1(Obj, Prop)) and default(object_property2(Obj, Prop, Extra)), I’d have a similar (but simpler) implementation of get but wouldn’t be able to see object_property1 solution provided by default if I did want to list all solutions.

But I do get your point. If we completely separate defaults from later-provided-values and don’t need to be able to list all solutions, including the default, the above may be a more efficient implementation.

I guess I need to figure out if I need to be able to list defaults. And if I do, maybe I need another predicate list_all that lists defaults and regular predicate values.

Thank you.