I have compound terms that can have a number inside the braces.
For example: qpowieipq(5),lsjdlasa(15) or lkjlk. I got it from the database (like my_list([rxclk,rxer,rxdv,rxd(0),rxd(1),rxd(2),crs,col,txen,txd(0),txd(1),txd(2),txd(3)]).).
How can I get the value of the number inside the braces?
For example:
my_function(qpowieipq(5), X).
X=5.
my_function(lsjdlasa(15), X).
X=15.
my_function(lkjlk, X).
false
I am using SWI Prolog.
You can use (=..)/2 and pattern matching to deconstruct Prolog's compound terms. For instance
?- a =.. X.
X = [a].
?- a(1) =.. X.
X = [a, 1].
So, tentatively
my_function(T, V) :- T =.. [_,V], number(V).
This will work with any ISO compliant Prolog processor.
Related
Just made a funny observation. SWI-Prolog allows other things than
atom as a functor in a compound. For example it allows me to do:
/* atom as functor */
?- Y =.. [foo, bar].
Y = foo(bar).
/* stream as functor */
?- current_input(X), Y =.. [X, bar].
X = <stream>(0000000069066420),
Y = <stream>(0000000069066420)(bar).
I wonder whether there is a name for what is allowed as a functor,
i.e atom or stream etc.. . The error message by SWI-Prolog doesn't
tell me what is the name, it says it expects an atom:
?- Y =.. [1, bar].
ERROR: Type error: `atom' expected, found `1' (an integer)
But as can be seen a stream etc.. , which is accepted, is not an atom:
?- current_input(X), atom(X).
false.
What is the umbrella type for what SWI-Prolog accepts as functor?
P.S. My guess why this is allowed: It is for example used for Dicts,
dicts are compounds with a special functor C'dict'.
Edit 10.09.2021:
I first thought its simple/1. But simple/1 is reserved
for atom or var, according to this answer:
What is the meaning of predicate "simple/1" in Prolog (SWI-Prolog)
In SWI-Prolog, blobs (binary large objects) are used to store arbitrary binary data, including atoms, images, and stream handles. Particularly, a blob represening a stream handle is a unique symbol which has no syntactical representation (although it is outputted as <stream>(hex-number)).
The built-in predicate blob/2 can be used to get the type of a blob:
?- X = foo, blob(X,Y).
X = foo,
Y = text.
?- current_input(X), blob(X,Y).
X = <stream>(0000000069057160),
Y = stream.
Thus, I think the type accepted as functor in SWI-Prolog is blob.
In Dogelog Runtime we recently introduced a new type tester called symbol/1. One can imagine that it is bootstrapped from blob/2 as follows:
symbol(X) :- blob(X, _).
Dogelog Runtime does also accept symbols as functors, similar like SWI-Prolog. This is used to inline disjunction and if-then-else, and could have further optimization use cases. Functors are not only restricted to atoms, they can be atoms or references:
/* Dogelog Runtime, 0.9.6 */
?- current_input(X), atom(X).
fail.
?- current_input(X), Y =.. [X, bar].
X = [object Object], Y = [object Object](bar).
But I am currently thinking about extending (=..)/2 even more. Namely to allow a compound as functor. What should a compound as functor do? Very simple:
/* Expected Result */
?- X =.. [foo(bar), baz].
X = foo(bar, baz)
So (=..)/2 would add the arguments to the given compound. This further extension of (=..)/2 doesn't need a new data type in the compound functor, but rather changes its behaviour.
It would have a couple of use cases:
Old Higher Order:
Bootstrapping apply/2 would be as easy as:
apply(X,L) :- G =.. [X|L], G.
New Higher Order:
Bottstrapping call/n would be as easy as:
call(X,Y) :- G =.. [X,Y], G.
call(X,Y,Z) :- G =.. [X,Y,Z], G.
call(X,Y,Z,T) :- G =.. [X,Y,Z,T], G.
Etc..
DCG Expansion:
Expanding a non-terminal by an input and output list would be only a matter of calling (=..)/2. Here is an example:
?- G =.. [np(X),I,O].
G = np(X,I,O).
This one tickled my interest in theory:
Is it possible to write an inconsistent Prolog program, i.e. a program that answers both false and true depending on how it is queried, using only pure Prolog, the cut, and false?
For example, one could query p(1) and the Prolog Processor would says false. But when one queries p(X) the Prolog Processor would give the set of answers 1, 2, 3.
This can be easily achieved with "computational state examination predicates" like var/1 (really better called fresh/1) + el cut:
p(X) :- nonvar(X),!,member(X,[2,3]).
p(X) :- member(X,[1,2,3]).
Then
?- p(1).
false.
?- p(X).
X = 1 ;
X = 2 ;
X = 3.
"Ouch time" ensues if this is high-assurance software. Naturally, any imperative program has no problem going off the rails like this on every other line.
So. can be done without those "computational state examination predicates"?
P.S.
The above illustrates that all the predicates of Prolog are really carrying a threaded hidden argument of the "computational state":
p(X,StateIn,StateOut).
which can be used to explain the behavour of var/1 and friends. The Prolog program is then "pure" when it only calls predicates that neither consult not modify that State. Well, at least that seems to be a good way to look at what is going on. I think.
Here's a very simple one:
f(X,X) :- !, false.
f(0,1).
Then:
| ?- f(0,1).
yes
| ?- f(X,1).
no
| ?- f(0,Y).
no
So Prolog claims there are no solutions to the queries with variables, although f(0,1) is true and would be a solution to both.
Here is one attempt. The basic idea is that X is a variable iff it can be unified with both a and b. But of course we can't write this as X = a, X = b. So we need a "unifiable" test that succeeds without binding variables like =/2 does.
First, we need to define negation ourselves, since it's impure:
my_not(Goal) :-
call(Goal),
!,
false.
my_not(_Goal).
This is only acceptable if your notion of pure Prolog includes call/1. Let's say that it does :-)
Now we can check for unifiability by using =/2 and the "not not" pattern to preserve success while undoing bindings:
unifiable(X, Y) :-
my_not(my_not(X = Y)).
Now we have the tools to define var/nonvar checks:
my_var(X) :-
unifiable(X, a),
unifiable(X, b).
my_nonvar(X) :-
not(my_var(X)).
Let's check this:
?- my_var(X).
true.
?- my_var(1).
false.
?- my_var(a).
false.
?- my_var(f(X)).
false.
?- my_nonvar(X).
false.
?- my_nonvar(1).
true.
?- my_nonvar(a).
true.
?- my_nonvar(f(X)).
true.
The rest is just your definition:
p(X) :-
my_nonvar(X),
!,
member(X, [2, 3]).
p(X) :-
member(X, [1, 2, 3]).
Which gives:
?- p(X).
X = 1 ;
X = 2 ;
X = 3.
?- p(1).
false.
Edit: The use of call/1 is not essential, and it's interesting to write out the solution without it:
not_unifiable(X, Y) :-
X = Y,
!,
false.
not_unifiable(_X, _Y).
unifiable(X, Y) :-
not_unifiable(X, Y),
!,
false.
unifiable(_X, _Y).
Look at those second clauses of each of these predicates. They are the same! Reading these clauses declaratively, any two terms are not unifiable, but also any two terms are unifiable! Of course you cannot read these clauses declaratively because of the cut. But I find this especially striking as an illustration of how catastrophically impure the cut is.
I wrote a test program with bindings (facts) between atoms and numbers.
bind(a, 3).
bind(b, 4).
bind(c, 5).
As part of a toy interpreter, I want to be able to perform additions on these atoms using Prolog's native arithmetic operators. For instance, I want to be able to run this query:
% val(X) is the value bound to X
?- X is val(a) + val(b).
X = 7.
However, I'm struggling to find a way to allow this addition. My first approach would have been this one:
% val(X, Y): Y is the value bound to X
val(X, Y) :- bind(X, Y).
% Make val an arithmetic function
:- arithmetic_function(val/1).
However, arithmetic_function/1 is no longer part of Prolog (or at least SWI-Prolog says it's deprecated), so I can't use it. Then I believed the best solution would be to overload the + operator to take this into account:
% val(X, Y): Y is the value bound to X
val(val(X), Y) :- bind(X, Y).
% Overload the + operator
+(val(_X, XVal), val(_Y, YVal)) :- XVal + YVal.
But here I've got my syntax all messed up because I don't really know how to overload a native arithmetic operation. When I type in the sample query from before, SWI-Prolog says ERROR: Arithmetic: ``val(a)' is not a function.
Would you have hints about a possible solution or a better approach or something I missed?
From the docs, I tought you should use function_expansion/3.
But I'm unable to get it to work, instead, goal_expansion could do, but isn't very attractive... for instance, if you save the following definitions in a file bind.pl (just to say)
:- module(bind, [test/0]).
:- dynamic bind/2.
bind(a, 3).
bind(b, 4).
bind(c, 5).
% :- multifile user:goal_expansion/2.
user:goal_expansion(val(X), Y) :- bind(X, Y).
user:goal_expansion(X is Y, X is Z) :- expand_goal(Y, Z).
user:goal_expansion(X + Y, U + V) :- expand_goal(X, U), expand_goal(Y, V).
test :-
X is val(a) + val(b), writeln(X).
and consult it, you can run your test:
?- test.
7
edit
after Paulo suggestion, here is an enhanced solution, that should work for every binary expression.
user:goal_expansion(X is Y, X is Z) :- expr_bind(Y, Z).
expr_bind(val(A), V) :- !, bind(A, V).
expr_bind(X, Y) :-
X =.. [F, L, R], % get operator F and Left,Right expressions
expr_bind(L, S), % bind Left expression
expr_bind(R, T), % bind Right expression
Y =.. [F, S, T]. % pack bound expressions back with same operator
expr_bind(X, X). % oops, I forgot... this clause allows numbers and variables
having defined user as target module for goal_expansion, it works on the CLI:
?- R is val(a)*val(b)-val(c).
R = 7.
edit
now, let's generalize to some other arithmetic operators, using the same skeleton expr_bind uses for binary expressions:
user:goal_expansion(X, Y) :-
X =.. [F,L,R], memberchk(F, [is, =<, <, =:=, >, >=]),
expr_bind(L, S),
expr_bind(R, T),
Y =.. [F, S, T].
and unary operators (I cannot recall no one apart minus, so I show a simpler way than (=..)/2):
...
expr_bind(-X, -Y) :- expr_bind(X, Y).
expr_bind(X, X).
Now we get
?- -val(a)*2 < val(b)-val(c).
true.
One way to do it is using Logtalk parametric objects (Logtalk runs on SWI-Prolog and 11 other Prolog systems; this makes this solution highly portable). The idea is to define each arithmetic operation as a parametric object that understands an eval/1 message. First we define a protocol that will be implemented by the objects representing the arithmetic operations:
:- protocol(eval).
:- public(eval/1).
:- end_protocol.
The basic parametric object understands val/1 and contains the bind/2 table:
:- object(val(_X_), implements(eval)).
eval(X) :-
bind(_X_, X).
bind(a, 3).
bind(b, 4).
bind(c, 5).
:- end_object.
I exemplify here only the implementation for arithmetic addition:
:- object(_X_ + _Y_, implements(eval)).
eval(Result) :-
_X_::eval(X), _Y_::eval(Y),
Result is X + Y.
:- end_object.
Sample call (assuming the entities above are saved in an eval.lgt file):
% swilgt
...
?- {eval}.
% [ /Users/pmoura/Desktop/eval.lgt loaded ]
% (0 warnings)
true.
?- (val(a) + val(b))::eval(R).
R = 7.
This can be an interesting solution if you plan to implement more functionality other than expression evaluation. E.g. a similar solution but for symbolic differentiation of arithmetic expressions can be found at:
https://github.com/LogtalkDotOrg/logtalk3/tree/master/examples/symdiff
This solution will also work in the case of runtime generated expressions (term-expansion based solutions usually only work at source file compile time and at the top-level).
If you're only interested in expression evaluation, Capelli's solution is more compact and retains is/2 for evaluation. It can also be made more portable if necessary using Logtalk's portable term-expansion mechanism (but note the caveat in the previous paragraph).
This is perhaps not exactly what I was looking for, but I had an idea:
compute(val(X) + val(Y), Out) :-
bind(X, XVal),
bind(Y, YVal),
Out is XVal + YVal.
Now I can run the following query:
?- compute(val(a) + val(c), Out).
Out = 8.
Now I need to define compute for every arithmetic operation I'm interested in, then get my interpreter to run expressions through it.
I'm new to Prolog and would like to define a simple predicate which calculates the result depending on which function I choose to use in the arithmetic expression.
So, this was my idea:
operation(X,Y, Op, Result):-
Result is X Op Y.
Now, I was expecting this from Prolog:
operation(3,4,'+', X).
X = 7.
But as you can probably guess, Prolog cannot identify Op as an arithmetic operation.
Does anyone have an idea how this is possible?
I could not find anything on the internet yet, even though it is rather basic, I think.
Thanks in advance!
Although the answers by Tudor and gokhans deliver the wanted result, I think there is a more elegant solution.
Portable solution
The following will work in most Prolog implementations:
operation(X, Y, Operator, Result):-
Goal =.. [Operator, X, Y],
Result is Goal.
Extended but SWI-Prolog specific solution
SWI-Prolog allows the definition of custom arithmetic functions. The following code extends the above for use with such user-defined functions coming from other modules:
:- meta_predicate(operation(+,+,2,-)).
operation(X, Y, Module:Operator, Result):-
Goal =.. [Operator, X, Y],
Module:(Result is Goal).
Notice that support for user-defined functions is deprecated in SWI-Prolog and does not work in other Prologs that do not have this feature.
Usage examples
Some examples of using these implementations of operation/4:
?- operation(1, 2, mod, X).
X = 1.
?- operation(1, 2, //, X).
X = 0.
?- operation(1, 2, /, X).
X = 0.5.
?- operation(1, 2, -, X).
X = -1.
?- operation(1, 2, +, X).
X = 3.
You need to tell Prolog if Op is '+' then sum X and Y. You can do that as following
operation(X,Y, Op, Result) :-
Op = '+',
Result is X + Y
;
Op = '-',
Result is X - Y.
You can increase number of operations.
I have an assignment question like so:
Write a program to find the last element of a list. e.g.
?- last(X, [how, are, you]).
X = you
Yes
I'm currently finding the last element like this:
last([Y]) :-
write('Last element ==> '),write(Y).
last([Y|Tail]):-
last(Tail).
And it works. My question is, how do I change it to accept and set the addition X parameter and set it correctly?
I tried this, but it's not working ...
last(X, [Y]) :-
X is Y.
last(X, [Y|Tail]):-
last(X, Tail).
Most obvious problem: (is)/2 works with numbers only. (link)
-Number is +Expr
True when Number is the value to which Expr evaluates
You want to use the unification operator (=)/2 (link):
last(X, [Y]) :-
X = Y,
!.
last(X, [_|Tail]):-
last(X, Tail).
Let's try:
?- last(X, [1, 2, 3]).
X = 3.
?- last(X, [a, b, c]).
X = c.
Using the unification operator is not the preferred way to unify in a case like this. You can use unification in a much more powerful way. See the following code:
last(Y, [Y]). %this uses pattern matching to Unify the last part of a list with the "place holder"
%writing this way is far more concise.
%the underscore represents the "anonymous" element, but basically means "Don't care"
last(X, [_|Tail]):-
last(X, Tail).