5

How can I add a function (e.g., hammingweight) and use it in expressions occuring in the right-hand side is some (is)/2 goal?

Could something like goal_expansion or term_expansion help here?

I acknowledge that this is not a big feature, but it could increase readability of some of my Prolog programs.

Writing a custom (is)/2 predicate (implementing a custom expression evaluator) is do-able, but I would like to keep runtime overhead low, as I don't want to sacrifice readability for runtime overhead in this case.

false
  • 10,264
  • 13
  • 101
  • 209
repeat
  • 18,496
  • 4
  • 54
  • 166

4 Answers4

3

There is no such provision in ISO Prolog, neither to extend (is)/2 nor to rely on goal expansion. And, looking at the various implementation specific features that are offered by some implementations to this end, there is no generally agreed upon way to do this. So implementing your own (my_is)/2 seems to be the best way to go.

Also note, that this would not only affect (is)/2 but also all other built-ins that use evaluable functors. In particular, all arithmetic comparison built-ins (8.7 Arithmetic comparison) (see this overview) would be affected.

false
  • 10,264
  • 13
  • 101
  • 209
2

My simple minded (~20 LOC) syntax sugar, lifter, it's based on goal_expansion.

With lifter, the clause

longer(A,B) :-
    length(A,º) > length(B,º).

is expanded to

longer(A, B) :-
    length(A, C),
    length(B, D),
    C > D.
CapelliC
  • 59,646
  • 5
  • 47
  • 90
  • The solution is a neat one but given the question is tagged as Prolog generic and `iso-prolog`, it's a good idea to note in the answer that the solution presented targets a specific Prolog implementation (SWI-Prolog, apparently, in this case). Otherwise, a user trying the solution in other Prolog implementation may end up with the wrong perception that that implementation is broken instead of simply providing a different feature set. – Paulo Moura Mar 04 '15 at 19:32
  • 1
    @PauloMoura: you're right. I was posting my solution just to provide a working sample of goal_expansion – CapelliC Mar 04 '15 at 19:42
  • Which the poster can likely use or adapt for his own purpose :-) – Paulo Moura Mar 04 '15 at 19:57
  • 1
    surely SICStus will support goal_expansion, isn't it ? – CapelliC Mar 05 '15 at 10:55
1

You can use Logtalk's term-expansion mechanism, which is portable and works with its twelve supported Prolog compilers (*). Logtalk compiling and loading and loading predicates accept Prolog files and will output the corresponding Prolog expanded files. For example, assuming that the file you want to expand is named source.pl and that your term_expansion/2 and goal_expansion/2 predicate definitions are in a file named expansions.pl, you can do something like:

% first, load the expansion hooks:
| ?- [expansions].
...

% second, expand a file using those hooks:
| ?- logtalk_compile(source, [hook(user)]).
...

You will get the expanded file, which will be (by default) named source_pl.pl (in a directory that will depend on the value of the scratch_directory Logtalk flag). If the expansions are contained in a Prolog module, use above the module name instead of user. If the source.pl file contains a module instead of plain Prolog code, you'll need to define some clauses for the term_expansion/2 predicate to avoid Logtalk compiling the module as an object. But in the simpler case where you're not using modules, the two queries above should suffice.

One feature of Logtalk's term-expansion mechanism that might be useful is that you can mark a term or a goal to not be expanded or further expanded by wrapping it with the {}/1 control construct.

(*) Note that term-expansion mechanism are not standard, not provided by all Prolog implementations, and with significant differences between implementations.

Paulo Moura
  • 18,373
  • 3
  • 23
  • 33
-1

Many Prolog systems don't allow user defined evaluable predicates. Sometimes the problem is that the evaluable predicates live in another namespace. Sometimes the Prolog system shyes away from jumping back into Prolog execution while doing an arithmetic evaluation in the host language.

Some Prolog systems have nevertheless user defined evaluable predicates, like ECLiPSe Prolog and Jekejeke Prolog. In Jekejeke Prolog the overhead was two fold. To my surprise in the new Dogelog runtime user definable evaluable predicates show an advantage:

/* Dogelog Runtime 0.9.5 */
fact(0, 1) :- !.
fact(N, X) :- M is N-1, fact(M, Y), X is Y*N.

fact2(0, 1) :- !.
fact2(N, X) :- X is fact2(N-1)*N.

for(_).
for(N) :- N > 1, M is N - 1, for(M).

% ?- time((for(1000), fact(1000, _), fail; true)).
% % Wall 1595 ms, trim 0 ms

% ?- time((for(1000), _ is fact2(1000), fail; true)).
% % Wall 1394 ms, trim 0 ms

I am attributing the slight speed advantage to the more concise formulation in fact2/2. The formulation uses less Prolog logical variables. And the user defined evaluable predicates capable (is)/2 internally does also no Prolog logical variables, the host language assigments that happen do not allocate

a Prolog logical variable or trail the same, so that in the end there is a speed-up.