Arithmetic_function/1

I found arithmetic_function/1 but it is deprecated. If arithmetic_expression_value/2 is supposed to accomplish the same thing, I don’t understand how. Is there a way to create custom arithmetic expression functions that isn’t deprecated? If not, I’d like to use arithmetic_function/1 but I’m not sure how to use it. Do I just create a predicate with an extra argument for the return value and declare it in arithmetic_function/1 as a directive?

I’d also like to define functions that can take list arguments but I’ve seen some discussion suggesting that this was never possible. Any ideas?

If I understand your problem correctly you have run into the problem many new to Prolog have run into with regards to using math expressions; I even had this problem.

You often here the saying that Prolog doesn’t have functions, only predicates, but that is not really true, see: Arithmetic Functions

The use of these is a bit deceptive in that is/2 has to be used, e.g.

?- X is 2 + 2.
X = 4.

Over the years I have come to think of Prolog not as a Turing complete programming language but a language to create models to solve problems and as such there are certain parts of Prolog that are used for modeling and there are parts that are embedded modeling with island grammars within Prolog and the arithmetic functions are one such island grammar that uses is as both an escape syntax into the island grammar and/or as a predicate to return the value of the arithmetic functions.

is/2 used as a predicate.

?- is(X,2+2).
X = 4.

Some other embedded modeling are constraint satisfaction, term rewriting and DCGs.

Also to expand ones thinking on this is other types of operators. (How Operators: Infix, Prefix, Postfix, or Mixfix (Distfix))

HTH


Can you give us some concrete examples. When you say list arguments I think of list (List Manipulation) but I also think of arguments (Option list processing)

1 Like

By list argument I meant something like sum(L) where L is a list of numbers. e.g.

?- S is sum([1,2,3]).
S = 6.

Pretty simple but I don’t know how to define the sum function and I’m not sure it’s even possible. But to clarify, I want to be able to define arithmetic expression functions in general, not just ones with list arguments.

Perhaps using foldl/4. See: library(apply): Apply predicates on a list

?- foldl(add,[1,2,3],0,Sum).
Sum = 6.

For more details see: Adding elements of a list in Prolog

Since this notes using a functional form in Prolog, I expect David will make an appearance.

The goal for me is custom arithmetic expression functions.

Lets call (is)/2 by its nickname eval. Eval will translate this into:

?- [](X), '.'(3, X, Y), '.'(2, Y, Z), '.'(1, Z, T), sum(T, S).

If all arithmetic functions are defined, and if eval allows sub results
that are not only numbers, you might indeed get the desired result.

You might then also get, what I guess Picat can do:

?- S is sum([1,2,1+2]).
S = 6.

On the other hand using plus I only get:

?- foldl(plus,[1,2,3],0,Sum).
Sum = 6.

?- foldl(plus,[1,2,1+2],0,Sum).
ERROR: Type error: `integer' expected, found `1+2' (a compound)

The arithmetic function interface was introduced when is/2 dropped support for Prolog-defined functions. The reason for that is that it requires (de)serialization of arithmetic objects to the Prolog stacks for intermediate results and requires the arithmetic code to be prepared to deal with stack shifts and garbage collection. This slows down expression evaluation quite a bit. As Prolog systems I viewed as most closely related also did not provide Prolog defined functions I decided to drop them. The arithmetic function declaration performs source code rewriting to get something comparable. In any case, functions are always from a set of numbers to a single output number.

If you want functional notation in Prolog, use one of the various functional notation extensions. If you want it below a predicate like is, define your own eval/2 or something similar.

Although arithmetic_function is deprecated, It won’t disappear and even if it would, you can copy the library from an old version and add it to your project. I mostly think this is not a technique that should be promoted.

2 Likes

I’m not going to pursue arithmetic_function/1 anymore. I can’t figure out how to use it anyway.

I do have a predicate which works, but it requires explicitly listing in the code all term names that should be considered as operators . I’ll just add calls to current_op/3 instead of listing each operator.

This answer hints at some misconceptions. First of all, operators have nothing to do with arithmetic evaluation. I can write A is 1+B, but this is just syntactic sugar using operators for is(A,+(1,B)). Arithmetic evaluation applies to the right argument of is/2 and both arguments of =:=/2, >/2, etc. applies simply mean that executing e.g., is/2 causes the implementation of is/2 to examine the right argument.
If it finds a term (e.g., +(1,B)) it performs arithmetic evaluation on the arguments, calls some (C) function to do the right operation (addition), etc. If the whole thing successfully evaluates to number is/2 unifies this number to whatever appears on the left side and succeeds or fails.

Arithmetic functions are terms that are recognized by the evaluation logic of is/2, etc.

The library(arithmetic) allows defining new arithmetic functions. So, we can define squared(X) to be the same as X^2, This means we define

squared(X,Y) :- Y is X^2.

Now the library rewrites A is sqrt(squared(X1-X2)+squared(Y1-Y2) as

Xd is X1-X2,
squared(Xd,X2),
Yd is Y1-Y2,
squared(Yd,Y2),
A is sqrt(X2+Y2).

That is all …

3 Likes

Not really a misconception, but a generalization. In my code, all of arithmetic functions that I want to support with is/2 are operators. I realize that not all arithmetic expression functions have corresponding operators and that not all operators have corresponding arithmetic functions. In my case though, making the assumption allows me to use all binary arithmetic operators without explicitly listing the ones to be used with is/2 instead of my numeric predicates.

I did figure out what I was doing wrong with library(arithmetic). I was declaring the arity of the predicate instead of the arity of the function. But it still won’t take a list with more than one member as an argument.

FWIW, IBM Prolog allowed calling arbitrary predicates, something like this (I forget the syntax):

range(X, Limit, []) :- X >= Limit, !.
range(X, Limit, [X|Xs]) :- range(?X+1, Limit, Xs]).

which would expand to

range(X, Limit, []) :- X >= Limit, !.
range(X, Limit, [X|Xs]) :-
    X2 is X+1,
    range(X2, Limit, Xs]).

It could also handle arbitrary predicates, by taking their last argument as the “result”:

incr(X, Incr) :- X + 1.

range(X, Limit, []) :- X >= Limit, !.
range(X, Limit, [X|Xs]) :- range(?incr(X), Limit, Xs]).

We already have something similar in SWI-Prolog with the “.” operator for dicts … would it make sense to make this more general?

So, since arithmetic_functions/1 doesn’t allow functions that take lists as arguments, I still have to use a predicate I wrote that I call resolve/2. It uses the same approach where it adds a variable argument term and then calls it. But since a “resolvable” term still can be an arithmetic function, the code has to determine which way to “resolve” the term. Here’s the code as it stand now:

resolve(N,N) :- integer(N), !.
resolve(T,N) :-	
	\+ is_list(T),					
	compound(T), !,				
	T =.. [Head | Args],
	resolve_compound(Head,Args,N).

resolve_compound(Op,Args,N) :-	
	length(Args,2),
	current_op(_,_,Op), !,   
	Args = [Arg1,Arg2],
	resolve(Arg1,N1),
	resolve(Arg2,N2),
	Callable =.. [ Op, N1, N2 ],
	N is Callable.

resolve_compound(Head,Args,N) :-		
	append(Args,[N],CallArgs),			
	Callable =.. [Head | CallArgs],
	Callable.

Sorry, I’m still not good at formatting in this forum. It doesn’t show my indentation. I had to remove my comments. They made quite a mess.

Yes, I agree that checking for any binary operator is not the best way to determine if is/2 should be used or if it should use a custom predicate, but I couldn’t think of a better way. This is where I thought someone might have a better idea.

One way is to know which things you define yourself and hand the rest to is/2 as it will complain if some function isn’t known. The other is the reverse using current_arithmetic_function/1

FYI

I changed your code so it formats correctly.

Instead of using the quote button " which puts a >at the start of each line, use the preformatted text button </> which bookends the selected text with ```.

```
resolve(N,N) :- integer(N), !.
```

which renders as

resolve(N,N) :- integer(N), !.

NB The default programming language for preformatted text is Prolog, you can also manually chose another language that is configured for this site, see Language highlighting

Don’t worry many new users are not aware of these features. :slightly_smiling_face:

Also take a look at
Discourse New User Guide
Markdown help
Markdown tutorial
Language highlighting

Arithmetic functions can be any arity. The easiest code for eval/2 is as follows.
You don’t need current_op/3, the evaluator only requires that a predicate f/n+1 is defined for an evaluable function f/n:

eval(X, Y) :- callable(X), !,
    X =.. [F|L],
    eval_list(L, Y, R),
    H =.. [F|R],
    call(H).
eval(X, X).

eval_list([], Y, [Y]).
eval_list([X|Y], Z, [P|Q]) :-
     eval(X, P),
     eval_list(Y, Z, Q).

Example runs:

?- eval(plus(1,2), X).
X = 3.
?- eval(plus(1,plus(2,3)), X).
X = 6.

The above evaluator predicate eval/2 implements a so called strict evaluation strategy. This means all arguments of a function are first evaluated before the arguments are applied to the function.

The strict evaluation strategy is not always desired, for example the Java if-then-else evaluable expression A ? B : C does not strictly evaluate A,B and C. It only evaluates B when A evaluated to true, and otherwise it evaluates C.

See also:

In strict evaluation, the arguments to a function are
always evaluated completely before the function is applied.
https://en.wikipedia.org/wiki/Evaluation_strategy#Strict_evaluation

Since Prolog is completely non-strict, arguments to a predicate are never evaluated, it can be used in teaching and practically, to implement evaluators that are strict or partially strict. Each predicate can decide what it evaluates or not.

You can therefore do the following as well:

less(X, Y) :-
    eval(X, A),
    eval(Y, B),
    A < B.

Works as well:

?- less(2, 1).
false.
?- less(2, plus(1,2)).
true.

Thanks Jan, current_arithmetic_function/1 is exactly what I need.

I thought prolog was the default? If not (and there can be a default), that should be the case. After all we are a Prolog forum :slight_smile:

A little related, it is great we can now attach .pl file, only they are marked as Perl by the browser :frowning: I think we need mime type application/x-prolog, but that may be for our self-hosted server …

Yes, Prolog is the default.

Had you not asked I would not have known this, thanks.

To verify this I did a little test and created the same preformatted text, one without prolog and one with prolog and then used the inspect HTML feature of an Internet browser, e.g. Chrome.

For both variations they modify the HMTL with

<code class="lang-prolog hljs">
</code>

Also checked that this was a Discourse option that can be set by admins.
It is Settings -> Postings -> default code lang

Default programming language syntax highlighting applied to GitHub code blocks (lang-auto, ruby, python etc.)

and it is set to prolog.