I want to declare a list of lists, like so:
%% example 1
Xs = [
[[A],[[A]]],
[[A],[[A],[A]]],
[[A],[[A],[A],[A]]]
].
Here, the symbol A refers to the same variable in each list. Executing maplist(writeln,xs) results in the following output:
[[_G1],[[_G1]]]
[[_G1],[[_G1],[_G1]]]
[[_G1],[[_G1],[_G1],[_G1]]]
I want to use the same symbol A in each list, but for the variable to be distinct for each list, to give the following output:
[[_G1],[[_G1]]]
[[_G2],[[_G2],[_G2]]]
[[_G3],[[_G3],[_G3],[_G3]]]
The only way I make this work is give each list its own unique variable, like so:
%% example 2
Xs = [
[[A1],[[A1]]],
[[A2],[[A2],[A2]]],
[[A3],[[A3],[A3],[A3]]]
].
Is there any Prolog syntax, so that there is no need to number each variable, as per example 2? I tried adding brackets around the lists like so:
Xs = [
([[A],[[A]]]),
([[A],[[A],[A]]]),
([[A],[[A],[A],[A]]])
].
But this gives me the same output as example 1.
Variable names in Prolog have a scope that spans a single clause in a predicate definition, or a query at the top-level. So, this:
?- List = [A, A, A].
means a list with three times the same variable, A. If you put it into a predicate, it would be, say in a file my_lists.pl (I have not nested the lists like you, just to keep it simple):
my_list([A, A]).
my_list([A, A, A]).
my_list([A, A, A, A]).
The As in the three clauses are now not in the same lexical scope, so if you consult this predicate and then collect all possible instantiations of my_list(L) using for example findall/3, you get what you are after:
?- [my_lists].
true.
?- findall(L, my_list(L), Ls).
Ls = [[_G1945, _G1945],
[_G1933, _G1933, _G1933],
[_G1918, _G1918, _G1918, _G1918]].
Is this close to what you are looking for? What is it that you are trying to achieve?
If you want to write out variables and specify a precise name for them, you need the write-option variable_names/1. This answer explains how. Alternatively, you might use the legacy predicate numbervars/3 which unifies distinct variables with a term '$VAR'(N), and then use either writeq/1 or the write-option numbervars(true).
But both methods will not work in the case you indicate. In fact, it was sheer luck that your query
?- Xs = [[[A],[A]],[[A],[A],[A]],[[A],[A],[A],[A]]], maplist(writeln,Xs).
produced the same variables for the different lists. It's even worse, the very same goal writing the very same list, may produce different variable names for different invocations:
p(N) :-
length(_,N),
length(K,1),
writeq(K),
garbage_collect,
writeq(K).
For p(100), SICStus writes [_776][_46], SWI writes [_G517][_G3]. Brief, you caught Prolog on a good day. This is not surprising, for the standard only requires an "implementation dependent" value for a name with a few restrictions: It starts with underscore, and the remaining characters are different for different variables, and the same for the same variable within the same write goal. Here is ISO/IEC 13211-1:1995 on this:
7.10.5 Writing a term
When a term Term is output using write_term/3 (8.14.2)
the action which is taken is defined by the rules below:
a) If Term is a variable, a character sequence repre-
senting that variable is output. The sequence begins
with _ (underscore) and the remaining characters are
implementation dependent. The same character sequence
is used for each occurrence of a particular variable in
Term. A different character sequence is used for each
distinct variable in Term.
The reason for this is that a globally consistent naming of variables would produce a lot of overhead in implementations.
To summarize: If you want to use different variable names for the same variable, then use variable_names/1 with different arguments. If you want the variable to be actually different, then name them differently, or use copy_term/2 accordingly.
You can do it like this:
First, create the desired list structure, with different variables:
?- maplist(length, Lists, [2,3,4]).
Lists = [[X1, X2], [X3, X4, X5], [X6, X7, X8, X9]].
Then, using the following additional definition:
same_element(Ls) :- maplist(=([_]), Ls).
you can unify variables that are in the same sublist to the same term:
?- maplist(same_element, [[X1, X2], [X3, X4, X5], [X6, X7, X8, X9]]).
X1 = X2, X2 = [_G1141],
X3 = X4, X4 = X5, X5 = [_G1149],
X6 = X7, X7 = X8, X8 = X9, X9 = [_G1157].
In combination:
?- maplist(length, Lists, [2,3,4]),
maplist(same_element, Lists),
maplist(writeln, Lists).
yielding:
[[_G1079],[_G1079]]
[[_G1087],[_G1087],[_G1087]]
[[_G1095],[_G1095],[_G1095],[_G1095]]
Now, with the following Emacs definitions:
(defun nice-variables (start end)
(interactive "r")
(goto-char start)
(let ((n 1)
(variables nil)
(m (make-marker)))
(set-marker m end)
(while (and (<= (point) (marker-position m))
(re-search-forward "_G" (marker-position m) t))
(let* ((from (point))
(len (skip-chars-forward "0-9"))
(str (buffer-substring-no-properties from (+ from len)))
(num (assoc str variables)))
(delete-backward-char (+ len 2))
(if num
(insert (format "X%d" (cdr num)))
(setq variables (cons (cons str n) variables))
(insert (format "X%d" n))
(setq n (1+ n)))))))
and M-x nice-variables RET on the region, you get:
[[X1],[X1]]
[[X2],[X2],[X2]]
[[X3],[X3],[X3],[X3]]
This is also what I used on the output of the first query above, to make it more readable.
Thus, you can either generate the structure you want dynamically, by unifying variables you want to be the same, or copy & paste the output above and use it with slight modifications in your program directly.
Related
So I have this mathematical language, it goes like this:
E -> number
[+,E,E,E] //e.g. [+,1,2,3] is 1+2+3 %we can put 2 to infinite Es here.
[-,E,E,E] //e.g. [-,1,2,3] is 1-2-3 %we can put 2 to infinite Es here.
[*,E,E,E] //e.g. [*,1,2,3] is 1*2*3 %we can put 2 to infinite Es here.
[^,E,E] //e.g. [^,2,3] is 2^3
[sin,E] //e.g. [sin,0] is sin 0
[cos,E] //e.g. [cos,0] is cos 0
and I want to write the set of rules that finds the numeric value of a mathematical expression written by this language in prolog.
I first wrote a function called "check", it checks to see if the list is written in a right way according to the language we have :
check1([]).
check1([L|Ls]):- number(L),check1(Ls).
check([L|Ls]):-atom(L),check1(Ls).
now I need to write the function "evaluate" that takes a list that is an expression written by this language, and a variable that is the numeric value corresponding to this language.
example:
?-evaluate([*,1,[^,2,2],[*,2,[+,[sin,0],5]]]],N) -> N = 40
so I wrote this:
sum([],0).
sum([L|Ls],N):- not(is_list(L)),sum(Ls,No),N is No + L.
min([],0).
min([L|Ls],N):-not(is_list(L)), min(Ls,No),N is No - L.
pro([],0).
pro([X],[X]).
pro([L|Ls],N):-not(is_list(L)), pro(Ls,No), N is No * L.
pow([L|Ls],N):-not(is_list(L)), N is L ^ Ls.
sin_(L,N):-not(is_list(L)), N is sin(L).
cos_(L,N):-not(is_list(L)), N is cos(L).
d([],0).
d([L|Ls],N):- L == '+' ,sum(Ls,N);
L == '-',min(Ls,N);
L == '*',pro(Ls,N);
L == '^',pow(Ls,N);
L == 'sin',sin_(Ls,N);
L == 'cos',cos_(Ls,N).
evaluate([],0).
evaluate([L|Ls],N):-
is_list(L) , check(L) , d(L,N),L is N,evaluate(Ls,N);
is_list(L), not(check(L)) , evaluate(Ls,N);
not(is_list(L)),not(is_list(Ls)),check([L|Ls]),d([L|Ls],N),
L is N,evaluate(Ls,N);
is_list(Ls),evaluate(Ls,N).
and it's working for just a list and returning the right answer , but not for multiple lists inside the main list, how should my code be?
The specification you work with looks like a production rule that describes that E (presumably short for Expression) might be a number or one of the 6 specified operations. That is the empty list [] is not an expression. So the fact
evaluate([],0).
should not be in your code. Your predicate sum/2 almost works the way you wrote it, except for the empty list and a list with a single element, that are not valid inputs according to your specification. But the predicates min/2 and pro/2 are not correct. Consider the following examples:
?- sum([1,2,3],X).
X = 6 % <- correct
?- sum([1],X).
X = 1 % <- incorrect
?- sum([],X).
X = 0 % <- incorrect
?- min([1,2,3],X).
X = -6 % <- incorrect
?- pro([1,2,3],X).
X = 6 ? ; % <- correct
X = 0 % <- incorrect
Mathematically speaking, addition and multiplication are associative but subtraction is not. In programming languages all three of these operations are usually left associative (see e.g. Operator associativity) to yield the mathematically correct result. That is, the sequence of subtractions in the above query would be calculated:
1-2-3 = (1-2)-3 = -4
The way you define a sequence of these operations resembles the following calculation:
[A,B,C]: ((0 op C) op B) op A
That works out fine for addition:
[1,2,3]: ((0 + 3) + 2) + 1 = 6
But it doesn't for subtraction:
[1,2,3]: ((0 - 3) - 2) - 1 = -6
And it is responsible for the second, incorrect solution when multiplying:
[1,2,3]: ((0 * 3) * 2) * 1 = 0
There are also some other issues with your code (see e.g. #lurker's comments), however, I won't go into further detail on that. Instead, I suggest a predicate that adheres closely to the specifying production rule. Since the grammar is describing expressions and you want to know the corresponding values, let's call it expr_val/2. Now let's describe top-down what an expression can be: It can be a number:
expr_val(X,X) :-
number(X).
It can be an arbitrarily long sequence of additions or subtractions or multiplications respectively. For the reasons above all three sequences should be evaluated in a left associative way. So it's tempting to use one rule for all of them:
expr_val([Op|Es],V) :-
sequenceoperator(Op), % Op is one of the 3 operations
exprseq_op_val(Es,Op,V). % V is the result of a sequence of Ops
The power function is given as a list with three elements, the first being ^ and the others being expressions. So that rule is pretty straightforward:
expr_val([^,E1,E2],V) :-
expr_val(E1,V1),
expr_val(E2,V2),
V is V1^V2.
The expressions for sine and cosine are both lists with two elements, the first being sin or cos and the second being an expression. Note that the argument of sin and cos is the angle in radians. If the second argument of the list yields the angle in radians you can use sin/1 and cos/2 as you did in your code. However, if you get the angle in degrees, you need to convert it to radians first. I include the latter case as an example, use the one that fits your application.
expr_val([sin,E],V) :-
expr_val(E,V1),
V is sin(V1*pi/180). % radians = degrees*pi/180
expr_val([cos,E],V) :-
expr_val(E,V1),
V is cos(V1*pi/180). % radians = degrees*pi/180
For the second rule of expr_val/2 you need to define the three possible sequence operators:
sequenceoperator(+).
sequenceoperator(-).
sequenceoperator(*).
And subsequently the predicate exprseq_op_val/3. As the leading operator has already been removed from the list in expr_val/2, the list has to have at least two elements according to your specification. In order to evaluate the sequence in a left associative way the value of the head of the list is passed as an accumulator to another predicate exprseq_op_val_/4
exprseq_op_val([E1,E2|Es],Op,V) :-
expr_val(E1,V1),
exprseq_op_val_([E2|Es],Op,V,V1).
that is describing the actual evaluation. There are basically two cases: If the list is empty then, regardless of the operator, the accumulator holds the result. Otherwise the list has at least one element. In that case another predicate, op_val_args/4, delivers the result of the respective operation (Acc1) that is then recursively passed as an accumulator to exprseq_op_val_/4 alongside with the tail of the list (Es):
exprseq_op_val_([],_Op,V,V).
exprseq_op_val_([E1|Es],Op,V,Acc0) :-
expr_val(E1,V1),
op_val_args(Op,Acc1,Acc0,V1),
exprseq_op_val_(Es,Op,V,Acc1).
At last you have to define op_val_args/4, that is again pretty straightforward:
op_val_args(+,V,V1,V2) :-
V is V1+V2.
op_val_args(-,V,V1,V2) :-
V is V1-V2.
op_val_args(*,V,V1,V2) :-
V is V1*V2.
Now let's see how this works. First your example query:
?- expr_val([*,1,[^,2,2],[*,2,[+,[sin,0],5]]],V).
V = 40.0 ? ;
no
The simplest expression according to your specification is a number:
?- expr_val(-3.14,V).
V = -3.14 ? ;
no
The empty list is not an expression:
?- expr_val([],V).
no
The operators +, - and * need at least 2 arguments:
?- expr_val([-],V).
no
?- expr_val([+,1],V).
no
?- expr_val([*,1,2],V).
V = 2 ? ;
no
?- expr_val([-,1,2,3],V).
V = -4 ? ;
no
The power function has exactly two arguments:
?- expr_val([^,1,2,3],V).
no
?- expr_val([^,2,3],V).
V = 8 ? ;
no
?- expr_val([^,2],V).
no
?- expr_val([^],V).
no
And so on...
This is a question provoked by an already deleted answer to this question. The issue could be summarized as follows:
Is it possible to fold over a list, with the tail of the list generated while folding?
Here is what I mean. Say I want to calculate the factorial (this is a silly example but it is just for demonstration), and decide to do it like this:
fac_a(N, F) :-
must_be(nonneg, N),
( N =< 1
-> F = 1
; numlist(2, N, [H|T]),
foldl(multiplication, T, H, F)
).
multiplication(X, Y, Z) :-
Z is Y * X.
Here, I need to generate the list that I give to foldl. However, I could do the same in constant memory (without generating the list and without using foldl):
fac_b(N, F) :-
must_be(nonneg, N),
( N =< 1
-> F = 1
; fac_b_1(2, N, 2, F)
).
fac_b_1(X, N, Acc, F) :-
( X < N
-> succ(X, X1),
Acc1 is X1 * Acc,
fac_b_1(X1, N, Acc1, F)
; Acc = F
).
The point here is that unlike the solution that uses foldl, this uses constant memory: no need for generating a list with all values!
Calculating a factorial is not the best example, but it is easier to follow for the stupidity that comes next.
Let's say that I am really afraid of loops (and recursion), and insist on calculating the factorial using a fold. I still would need a list, though. So here is what I might try:
fac_c(N, F) :-
must_be(nonneg, N),
( N =< 1
-> F = 1
; foldl(fac_foldl(N), [2|Back], 2-Back, F-[])
).
fac_foldl(N, X, Acc-Back, F-Rest) :-
( X < N
-> succ(X, X1),
F is Acc * X1,
Back = [X1|Rest]
; Acc = F,
Back = []
).
To my surprise, this works as intended. I can "seed" the fold with an initial value at the head of a partial list, and keep on adding the next element as I consume the current head. The definition of fac_foldl/4 is almost identical to the definition of fac_b_1/4 above: the only difference is that the state is maintained differently. My assumption here is that this should use constant memory: is that assumption wrong?
I know this is silly, but it could however be useful for folding over a list that cannot be known when the fold starts. In the original question we had to find a connected region, given a list of x-y coordinates. It is not enough to fold over the list of x-y coordinates once (you can however do it in two passes; note that there is at least one better way to do it, referenced in the same Wikipedia article, but this also uses multiple passes; altogether, the multiple-pass algorithms assume constant-time access to neighboring pixels!).
My own solution to the original "regions" question looks something like this:
set_region_rest([A|As], Region, Rest) :-
sort([A|As], [B|Bs]),
open_set_closed_rest([B], Bs, Region0, Rest),
sort(Region0, Region).
open_set_closed_rest([], Rest, [], Rest).
open_set_closed_rest([X-Y|As], Set, [X-Y|Closed0], Rest) :-
X0 is X-1, X1 is X + 1,
Y0 is Y-1, Y1 is Y + 1,
ord_intersection([X0-Y,X-Y0,X-Y1,X1-Y], Set, New, Set0),
append(New, As, Open),
open_set_closed_rest(Open, Set0, Closed0, Rest).
Using the same "technique" as above, we can twist this into a fold:
set_region_rest_foldl([A|As], Region, Rest) :-
sort([A|As], [B|Bs]),
foldl(region_foldl, [B|Back],
closed_rest(Region0, Bs)-Back,
closed_rest([], Rest)-[]),
!,
sort(Region0, Region).
region_foldl(X-Y,
closed_rest([X-Y|Closed0], Set)-Back,
closed_rest(Closed0, Set0)-Back0) :-
X0 is X-1, X1 is X + 1,
Y0 is Y-1, Y1 is Y + 1,
ord_intersection([X0-Y,X-Y0,X-Y1,X1-Y], Set, New, Set0),
append(New, Back0, Back).
This also "works". The fold leaves behind a choice point, because I haven't articulated the end condition as in fac_foldl/4 above, so I need a cut right after it (ugly).
The Questions
Is there a clean way of closing the list and removing the cut? In the factorial example, we know when to stop because we have additional information; however, in the second example, how do we notice that the back of the list should be the empty list?
Is there a hidden problem I am missing?
This looks like its somehow similar to the Implicit State with DCGs, but I have to admit I never quite got how that works; are these connected?
You are touching on several extremely interesting aspects of Prolog, each well worth several separate questions on its own. I will provide a high-level answer to your actual questions, and hope that you post follow-up questions on the points that are most interesting to you.
First, I will trim down the fragment to its essence:
essence(N) :-
foldl(essence_(N), [2|Back], Back, _).
essence_(N, X0, Back, Rest) :-
( X0 #< N ->
X1 #= X0 + 1,
Back = [X1|Rest]
; Back = []
).
Note that this prevents the creation of extremely large integers, so that we can really study the memory behaviour of this pattern.
To your first question: Yes, this runs in O(1) space (assuming constant space for arising integers).
Why? Because although you continuously create lists in Back = [X1|Rest], these lists can all be readily garbage collected because you are not referencing them anywhere.
To test memory aspects of your program, consider for example the following query, and limit the global stack of your Prolog system so that you can quickly detect growing memory by running out of (global) stack:
?- length(_, E),
N #= 2^E,
portray_clause(N),
essence(N),
false.
This yields:
1.
2.
...
8388608.
16777216.
etc.
It would be completely different if you referenced the list somewhere. For example:
essence(N) :-
foldl(essence_(N), [2|Back], Back, _),
Back = [].
With this very small change, the above query yields:
?- length(_, E),
N #= 2^E,
portray_clause(N),
essence(N),
false.
1.
2.
...
1048576.
ERROR: Out of global stack
Thus, whether a term is referenced somewhere can significantly influence the memory requirements of your program. This sounds quite frightening, but really is hardly an issue in practice: You either need the term, in which case you need to represent it in memory anyway, or you don't need the term, in which case it is simply no longer referenced in your program and becomes amenable to garbage collection. In fact, the amazing thing is rather that GC works so well in Prolog also for quite complex programs that not much needs to be said about it in many situations.
On to your second question: Clearly, using (->)/2 is almost always highly problematic in that it limits you to a particular direction of use, destroying the generality we expect from logical relations.
There are several solutions for this. If your CLP(FD) system supports zcompare/3 or a similar feature, you can write essence_/3 as follows:
essence_(N, X0, Back, Rest) :-
zcompare(C, X0, N),
closing(C, X0, Back, Rest).
closing(<, X0, [X1|Rest], Rest) :- X1 #= X0 + 1.
closing(=, _, [], _).
Another very nice meta-predicate called if_/3 was recently introduced in Indexing dif/2 by Ulrich Neumerkel and Stefan Kral. I leave implementing this with if_/3 as a very worthwhile and instructive exercise. Discussing this is well worth its own question!
On to the third question: How do states with DCGs relate to this? DCG notation is definitely useful if you want to pass around a global state to several predicates, where only a few of them need to access or modify the state, and most of them simply pass the state through. This is completely analogous to monads in Haskell.
The "normal" Prolog solution would be to extend each predicate with 2 arguments to describe the relation between the state before the call of the predicate, and the state after it. DCG notation lets you avoid this hassle.
Importantly, using DCG notation, you can copy imperative algorithms almost verbatim to Prolog, without the hassle of introducing many auxiliary arguments, even if you need global states. As an example for this, consider a fragment of Tarjan's strongly connected components algorithm in imperative terms:
function strongconnect(v)
// Set the depth index for v to the smallest unused index
v.index := index
v.lowlink := index
index := index + 1
S.push(v)
This clearly makes use of a global stack and index, which ordinarily would become new arguments that you need to pass around in all your predicates. Not so with DCG notation! For the moment, assume that the global entities are simply easily accessible, and so you can code the whole fragment in Prolog as:
scc_(V) -->
vindex_is_index(V),
vlowlink_is_index(V),
index_plus_one,
s_push(V),
This is a very good candidate for its own question, so consider this a teaser.
At last, I have a general remark: In my view, we are only at the beginning of finding a series of very powerful and general meta-predicates, and the solution space is still largely unexplored. call/N, maplist/[3,4], foldl/4 and other meta-predicates are definitely a good start. if_/3 has the potential to combine good performance with the generality we expect from Prolog predicates.
If your Prolog implementation supports freeze/2 or similar predicate (e.g. Swi-Prolog), then you can use following approach:
fac_list(L, N, Max) :-
(N >= Max, L = [Max], !)
;
freeze(L, (
L = [N|Rest],
N2 is N + 1,
fac_list(Rest, N2, Max)
)).
multiplication(X, Y, Z) :-
Z is Y * X.
factorial(N, Factorial) :-
fac_list(L, 1, N),
foldl(multiplication, L, 1, Factorial).
Example above first defines a predicate (fac_list) which creates a "lazy" list of increasing integer values starting from N up to maximum value (Max), where next list element is generated only after previous one was "accessed" (more on that below). Then, factorial just folds multiplication over lazy list, resulting in constant memory usage.
The key to understanding how this example works is remembering that Prolog lists are, in fact, just terms of arity 2 with name '.' (actually, in Swi-Prolog 7 the name was changed, but this is not important for this discussion), where first element represents list item and the second element represents tail (or terminating element - empty list, []). For example. [1, 2, 3] can be represented as:
.(1, .(2, .(3, [])))
Then, freeze is defined as follows:
freeze(+Var, :Goal)
Delay the execution of Goal until Var is bound
This means if we call:
freeze(L, L=[1|Tail]), L = [A|Rest].
then following steps will happen:
freeze(L, L=[1|Tail]) is called
Prolog "remembers" that when L will be unified with "anything", it needs to call L=[1|Tail]
L = [A|Rest] is called
Prolog unifies L with .(A, Rest)
This unification triggers execution of L=[1|Tail]
This, obviously, unifies L, which at this point is bound to .(A, Rest), with .(1, Tail)
As a result, A gets unified with 1.
We can extend this example as follows:
freeze(L1, L1=[1|L2]),
freeze(L2, L2=[2|L3]),
freeze(L3, L3=[3]),
L1 = [A|R2], % L1=[1|L2] is called at this point
R2 = [B|R3], % L2=[2|L3] is called at this point
R3 = [C]. % L3=[3] is called at this point
This works exactly like the previous example, except that it gradually generates 3 elements, instead of 1.
As per Boris's request, the second example implemented using freeze. Honestly, I'm not quite sure whether this answers the question, as the code (and, IMO, the problem) is rather contrived, but here it is. At least I hope this will give other people the idea what freeze might be useful for. For simplicity, I am using 1D problem instead of 2D, but changing the code to use 2 coordinates should be rather trivial.
The general idea is to have (1) function that generates new Open/Closed/Rest/etc. state based on previous one, (2) "infinite" list generator which can be told to "stop" generating new elements from the "outside", and (3) fold_step function which folds over "infinite" list, generating new state on each list item and, if that state is considered to be the last one, tells generator to halt.
It is worth to note that list's elements are used for no other reason but to inform generator to stop. All calculation state is stored inside accumulator.
Boris, please clarify whether this gives a solution to your problem. More precisely, what kind of data you were trying to pass to fold step handler (Item, Accumulator, Next Accumulator)?
adjacent(X, Y) :-
succ(X, Y) ;
succ(Y, X).
state_seq(State, L) :-
(State == halt -> L = [], !)
;
freeze(L, (
L = [H|T],
freeze(H, state_seq(H, T))
)).
fold_step(Item, Acc, NewAcc) :-
next_state(Acc, NewAcc),
NewAcc = _:_:_:NewRest,
(var(NewRest) ->
Item = next ;
Item = halt
).
next_state(Open:Set:Region:_Rest, NewOpen:NewSet:NewRegion:NewRest) :-
Open = [],
NewOpen = Open,
NewSet = Set,
NewRegion = Region,
NewRest = Set.
next_state(Open:Set:Region:Rest, NewOpen:NewSet:NewRegion:NewRest) :-
Open = [H|T],
partition(adjacent(H), Set, Adjacent, NotAdjacent),
append(Adjacent, T, NewOpen),
NewSet = NotAdjacent,
NewRegion = [H|Region],
NewRest = Rest.
set_region_rest(Ns, Region, Rest) :-
Ns = [H|T],
state_seq(next, L),
foldl(fold_step, L, [H]:T:[]:_, _:_:Region:Rest).
One fine improvement to the code above would be making fold_step a higher order function, passing it next_state as the first argument.
This is a test review question that I am having trouble with. How do you write a method to evaluate an algebraic expression with the operators plus,
minus and times. Here are some test queries:
simplify(Expression, Result, List)
?- simplify(plus(times(x,y),times(3 ,minus(x,y))),V,[x:4,y:2]).
V = 14
?- simplify(times(2,plus(a,b)),Val,[a:1,b:5]).
Val = 12
?- simplify(times(2,plus(a,b)),Val,[a:1,b:(-5)]).
Val = -8 .
All I was given were these sample queries and no other explanation. But I am pretty sure the method is supposed to dissect the first argument, which is the algebraic expression, substituting x and y for their values in the 3rd argument (List). The second argument should be the result after evaluating the expression.
I think one of the methods should be simplify(V, Val, L) :- member(V:Val, L).
Ideally there should only be 4 more methods... but I'm not sure how to go about this.
Start small, write down what you know.
simplify(plus(times(x,y),times(3 ,minus(x,y))),V,[x:4,y:2]):- V = 14.
is a perfectly good start: (+ (* 4 2) (* 3 (- 4 2))) = 8 + 3*2 = 14. But then, of course,
simplify(times(x,y),V,[x:4,y:2]):- V is 4*2.
is even better. Also,
simplify(minus(x,y),V,[x:4,y:2]):- V is 4-2.
simplify(plus(x,y),V,[x:4,y:2]):- V is 4+2.
simplify(x,V,[x:4,y:2]):- V is 4.
all perfectly good Prolog code. But of course what we really mean, it becomes apparent, is
simplify(A,V,L):- atom(A), getVal(A,L,V).
simplify(C,V,L):- compound(C), C =.. [F|T],
maplist( simp(L), T, VS), % get the values of subterms
calculate( F, VS, V). % calculate the final result
simp(L,A,V):- simplify(A,V,L). % just a different args order
etc. getVal/3 will need to retrieve the values somehow from the L list, and calculate/3 to actually perform the calculation, given a symbolic operation name and the list of calculated values.
Study maplist/3 and =../2.
(not finished, not tested).
OK, maplist was an overkill, as was =..: all your terms will probably be of the form op(A,B). So the definition can be simplified to
simplify(plus(A,B),V,L):-
simplify(A,V1,L),
simplify(B,V2,L),
V is V1 + V2. % we add, for plus
simplify(minus(A,B),V,L):-
% fill in the blanks
.....
V is V1 - V2. % we subtract, for minus
simplify(times(A,B),V,L):-
% fill in the blanks
.....
V is .... . % for times we ...
simplify(A,V,L):-
number(A),
V = .... . % if A is a number, then the answer is ...
and the last possibility is, x or y etc., that satisfy atom/1.
simplify(A,V,L):-
atom(A),
retrieve(A,V,L).
So the last call from the above clause could look like retrieve(x,V,[x:4, y:3]), or it could look like retrieve(y,V,[x:4, y:3]). It should be a straightforward affair to implement.
This question already has an answer here:
Evaluating an algebraic expression
(1 answer)
Closed 9 years ago.
This is a test review question that I am having trouble with. How do you write a method to evaluate an algebraic expression with the operators 'plus', 'minus' and 'times'. Here are some test queries:
simplify(Expression, Result, List)
?- simplify(plus(times(x,y),times(3 ,minus(x,y))),V,[x:4,y:2]). V = 14
?- simplify(times(2,plus(a,b)),Val,[a:1,b:5]). Val = 12
?- simplify(times(2,plus(a,b)),Val,[a:1,b:(-5)]). Val = -8
All I was given were these sample queries and no other explanation. But I am pretty sure the method is supposed to dissect the first argument, which is the algebraic expression, substituting x and y for their values in the 3rd argument (List). The second argument should be the result after evaluating the expression.
I think one of the methods should be simplify(V, Val, L) :- member(V:Val, L). Ideally there should only be 4 more methods... but I'm not sure how to go about this.
What I have so far but I don't know what the body should be:
simplify(Var, Value, Lst) :- member(Var:Value, Lst).
simplify(plus(Var), Value, Lst) :-
simplify(minus(Var), Value, Lst) :-
simplify(times(Var), Value, Lst) :-
I am not sure what the 5th method should be.
I suspect you've allowed yourself to get snowed by complex examples. You're just missing one base case and all the inductive cases are really simple. You just need some simpler examples. For starters, what should this return?
?- simplify(3, Val, []).
Yeah, Val = 3. So let's add that missing base case:
simplify(Num, Num, _) :- number(Num).
The key insight to the inductive casess is that plus, minus and times all have the same recursive binary structure. You can recursively apply simplify to both sides to achieve to evaluate things. Let's try another simple example:
?- simplify(times(3, 3), Val, []).
We want Val = 9. All we need to do is figure out what the left and right values are and multiply them together. So it will wind up looking like this:
simplify(times(Left, Right), Value, Lst) :-
simplify(Left, LeftVal, Lst),
simplify(Right, RightVal, Lst),
Value is LeftVal * RightVal.
You want to pass Lst on to the recursive invocations so they can look up variables too. From here you should be able to extrapolate what the plus and minus cases are going to look like. You really shouldn't need cases that look like plus(X) since that only has one argument.
The magic of Prolog is that this is really all you have to do. Recursion will take care of your complex examples as soon as you have the simple ones working. Try it. :)
Hope this helps!
I need to check if each element in second list has 3 times more instances then the same element in the first list. My function returns false all the time and I don't know what I'm dong wrong.
Here is the code:
fourth(_,[ ]).
fourth(A,[HF|TF]) :-
intersection(A, HF, NewA),
intersection(TF, HF, NewB),
append(HF, NewB, NewT),
append(NewA, NewA, NewAA),
append(NewA, NewAA, NewAAA),
length(NewAAA) == length(NewT),
select(HF, TF, NewTF),
fourth(A, NewTF).
Example:
?- fourth([1,2,3], [1,1,1]).
true.
?- fourth([1,2,3], [1,1,1,1]).
false.
?- fourth([1,2,3], [1,1]).
false.
?- fourth([1,2,2,3], [1,1,2,2,1,2,2,2,2]).
true.
I would make myself a select/3 predicate: select(X,From,Left), and then for each elt of a first list I'd call it three times with same first argument on a second list, progressively passing it forward, getting me a final Left3 without the three occurences of X; iand I'd do that for each elt of a first list. Then if I'd succeed and end up with an empty list, that means it had exactly three times each elt from the first list.
Your code seems needlessly complicated. It also contains bugs where you use HF instead of the list [HF].
So what's the logic you want to implement?:
take the next element from the second list (leaving the tail)
check if it's in the first list, and if it is, remove it (else fail)
remove it two more times from the tail of the second list
and this gives:
fourth(_,[ ]).
fourth(A,[HF|TF]) :-
once(select(HF, A, AR)), % using once/1 to avoid choicepoints
once(select(HF, TF, TF1)),
once(select(HF, TF1, TFR)),
fourth(AR, TFR).
Here is your code with suggestions on why it fails :
fourth(_,[]).
fourth(A,[HF|TF]) :-
intersection(A, HF, NewA),
intersection(TF, HF, NewB),
It's not intersection/3 that you want to use, for two reasons :
1) it doesn't filter only HF in A.
2) it fails if you call it with an element, so at least use [HF] instead
of HF
Instead, use include/3 : include(=(HF), A, NewA). See SWI-pl doc for more info.
append(HF, NewB, NewT),
append(NewA, NewA, NewAA),
append(NewA, NewAA, NewAAA),
Use of append/2 is better, especially for your NewAAA list.
length(NewAAA) == length(NewT),
You can't compare lengths like that. First, length/1 doesn't exist in
built-in swi-pl predicates. Instead, compare directly the lists or use
length/2 twice and then compare the results.
select(HF, TF, NewTF),
fourth(A, NewTF).
Only removing once HT in TF will cause your algorithm to fail. You need
to remove all the occurrences of HT in TF, with subtract/3 for example...
If you want a working solution respecting your original work, I'll add it, so feel free to ask, but as it was tagged homework I'll let you those working leads first...
% Blocks in our "block world"
%
% b3
% b4 b7
% b1 b5 b8
% b2 b6 b9
%==============
% Block Stacking
on(b1,b2).
on(b3,b4).
on(b4,b5).
on(b5,b6).
on(b7,b8).
on(b8,b9).
% Stack order
left(b2,b6).
left(b6,b9).
% Generalize "above"
above(Above,Below) :- on(Above,Below).
above(Above,Below) :- on(Above,AnyBlock), above(AnyBlock,Below).
% isLeft(X,Y) resolves to true if X is a block left of any block Y.
% isLeft/2 simply invokes leftOf/2 followed by a cut (!) to guarantee that
% only one result is generated.
%
% For Example: isleft(b1,b7) produces true
% isleft(b2,b6) produces true
% isleft(b4,b5) produces false.
% isleft(b9,b3) produces false.
isLeft(X,Y) :- leftOf(X,Y), !.
% Show an implementation of leftOf below. The implementation will involve a
% few cases (like the above predicate above), but can be completed using only the
% provided left and above predicates.