Transparent shift/1 wanted

I have found the following two lines solves my trouble for
“unknown procedure” error for “shifted” call.

:- meta_predicate shift_ala_phrase(:).
shift_ala_phrase(X):- shift(X).

Kuniaki Mukai

So far I use shift/1 of shift/reset in a way like the meta predicate phrase of DCG for hiding states like Haskel monad. However, restructuring my ZDD library, I noticed that shift/1 is not a meta_predicate.

    	?- predicate_property(shift(_), P).
	?- predicate_property(call(_), P). 

That is, the shift is not transparent at all. In my use of shift/reset, shifted “ball” Ball by shift(Ball) is always used in the form call(Ball, S) afterward for a state S given from reset. Non-transparency of shift for such use is inconvenient for restructuring codes so as to see many “unknown predicate” execution errors.
Although this is an abuse of shift of mine, as a DCG user, it seems a reasonable usage. I would like to see a new meta predicate shift_ala_phrase/1 added to shift/reset related predicates in the future.

Kuniaki Mukai

I’m afraid I need a running example that indicates the problem. shift/1 as such has no reason to be aware of modules. Possibly the stack snapshot needs to preserve more information, but without a concrete example I can’t really tell.

As I edited my help question, I have solved it for myself":

:- meta_predicate shift_ala_phrase(:).
shift_ala_phrase(X):- shift(X).

Without reading doc on shift carefully, I thought shift/2 is a meta predicate. Is there some reason why shift/1 is not a meta predicate ?
shift and phrase look similar.

Kuniaki Mukai

The ball is basically unrelated to modules. I think the question is close to why throw/1 is not a meta-predicate. There can of course be reasons that you want to include the module into the ball. If so, your proposal makes sense. Just declaring shift/1 is a meta-predicate most likely breaks a lot of code for no good reason. I’d need a concrete example of the code to see whether what you are doing is how shift/reset are supposed to be used. But hey, many predicates find applications the developers have not anticipated :slight_smile:

Hi Jan,

Thank you for reply. I see your point on shift and throw. I agree. This is a concrete example on your request, though it is not complete one, but I hope my use of balls shifted are always used only in the form of call(ball). My main purpose of using shift is to hide state from programming on ZDD like phrase to hide string from programming on given a grammar, though this may be my superficial impression on shift/reset. Anyway it turned out very useful for the current purpose of mine. Overhead of shift/reset seems good as far as profile tells, though I am occupied only for first climbing high two walls of ZDD (counting paths and associative algebras).

% ?-  zdd((X<< pow([a,b]), card(X, C), psa(X)))
%@ 
%@ zdd 3:
%@ 	[]
%@ 	[b]
%@ 	[a]
%@ 	[a,b]
%@ X = 3,
%@ C = 4.

where, pow is for powerset, card is for cardinality, psa is for printing a zdd in state at X for debugging. This is a complete source listing of card/2, in which shift is used as a la phrase/1,2,3 in the typical usage of shift in my ZDD package. There is no other way of use.

card(X, Y):- shift(card(X, Y)).
%

card(X, Y, S):- setup_call_cleanup(	open_memo(M),
	card(X, Y, S, M),
	close_memo(M)).

card(I, I, _, _):- I < 2, !.
card(I, C, S, M):- memo(I-C, M),
	(	nonvar(C) -> true
	;	cofact(I, t(_, L, R), S),
		card(R, Cr, S, M),
		card(L, Cl, S, M),
		C is Cl + Cr
	).
zdd(E):- context_module(M),
	setup_call_cleanup(
		open_state(S),
		zdd(E, S, M),
		close_state(S)).
%
zdd((A,B), S, M):-!, zdd(A, S, M), zdd(B, S, M).
zdd(X<<E, S, _):-!, zdd_eval(E, X, S).
zdd(M:G, S, _):-!, zdd(G, S, M).
zdd(0, _, _):-!.
zdd(true, _, _):-!.
zdd({G}, _, _):-!, call(G).
zdd((A;B), S, M):-!, (zdd(A, S, M); zdd(B, S, M)).
zdd((A->B), S, M):-!, (zdd(A, S, M)->zdd(B, S, M)).
zdd(Cont, S, M):- reset(M:Cont, Ball, Cont0),
	(	var(Ball) -> true
	;	call(Ball, S)
	),
	zdd(Cont0, S, M).

%
zdd_eval(X, X, _)	:-integer(X), !.  % for any x >= 0.
zdd_eval(L, Y, S)	:-is_list(L), !, sort(L, L0),
	list_to_path(L0, Y, S).
zdd_eval({X}, Y, S)	:-!, comma_to_list(X, U, []), zdd_family(U, Y, S).
zdd_eval(dnf(A), X, S):-!, expand_boole_macro(A, A0),
	boole_to_dnf(A0, X, S).
zdd_eval(cnf(A), X, S):-!, expand_boole_macro(A, A0),
	boole_to_cnf(A0, X, S).
zdd_eval(X + Y, A1, S):-!, zdd_eval(X, A2, S),
	zdd_eval(Y, A3, S),
	zdd_join(A2, A3, A1, S).
zdd_eval(X * Y, A1, S):-!, zdd_eval(X, A2, S),
	zdd_eval(Y, A3, S),
	zdd_meet(A2, A3, A1, S).
zdd_eval(X - Y, A1, S):-!, zdd_eval(X, A2, S),
	zdd_eval(Y, A3, S),
	zdd_subtr(A2, A3, A1, S).
zdd_eval(\(X,Y), A, S):-!, zdd_eval(X-Y, A, S).
zdd_eval(merge(X, Y), A1, S):-!, zdd_eval(X, A2, S),
	zdd_eval(Y, A3, S),
	zdd_merge(A2, A3, A1, S).
zdd_eval(&(X, Y), A, S):-!, zdd_eval(merge(X, Y), A, S).
zdd_eval(prod(X, Y), A1, S):-!, zdd_eval(X, A2, S),
	zdd_eval(Y, A3, S),
	zdd_product(A2, A3, A1, S).
zdd_eval(**(X, Y), A, S):-!,	zdd_eval(prod(X, Y), A, S).
zdd_eval(pow(X), A, S) :-!,  zdd_power(X, A, S).
zdd_eval(power(X), A, S):-!, zdd_eval(pow(X), A, S).
zdd_eval(sets(X), A, S)	:-!, zdd_eval(X, Y, S),
	sets(Y, A, S).
zdd_eval(zdd(E), A, S)	:-!, call(E, A, S).
zdd_eval(Other, A, S)	:- call(Other, B), zdd_eval(B, A, S).

Kuniaki Mukai

Hmm. Seems all the shift/reset is doing is to give some call access to some variable that is only known higher up in the call tree, right? Seems you can also get there the classical way using program transformation or the tricky way discussed here recently by inspecting the stack, looking for the right zdd parent goal. That only requires a scan of the stacks rather than copying them.

| jan
October 18 |

  • | - |

kuniaki.mukai:

zdd(Cont, S, M):- reset(M:Cont, Ball, Cont0),
	(	var(Ball) -> true
	;	call(Ball, S)
	),
	zdd(Cont0, S, M).

Hmm. Seems all the shift/reset is doing is to give some call access to some variable that is only known higher up in the call tree, right?

Perhaps Yes. In fact before I knew shift/reset, I did it using global variables with b_setval/b_getval.

Seems you can also get there the classical way using program transformation or the tricky way discussed here recently by inspecting the stack, looking for the right zdd parent goal. That only requires a scan of the stacks rather than copying them.

The stack is a kind of sacred place into which only selected priests are allowed to enter. At least for the time being, I should be satisfied with my current use of shift/reset.

Thank you for comments.

Kuniaki Mukai