/* USEFUL.PL */ /* :- module useful. :- public real/1, numeric/1, max/3, min/3, abolish/2, clause_vs_head_tail_pred_arity/5, clause_vs_head_tail/3, clause_vs_pred_arity/3, conj_vs_list/2, round_term_vs_list/4, is_system_pred/2, is_system_goal/1, get_prompt/1, set_prompt/1, add_portray/1, del_portray/1. */ /* SPECIFICATION ------------- This module exports a few generally useful predicates. The first two predicates, 'real' and 'numeric' provide type-tests that ought to exist in Poplog Prolog (or any other implementation with real numbers) but are unaccountably absent. 'abolish' ought also to exist in your Prolog, as it does in mine. If it isn't there, use the definition below. 'max' and 'min' do what you'd expect, as do 'set/get_prompt' and 'is_system_pred/goal'. 'head_tail_arity_pred' is useful for taking clauses apart and decomposing their heads, as are its relatives. 'conj_vs_list' converts between "round lists" (conjunctions of goals) and lists. 'round_term_vs_list' does the same, but the operator need not be comma. So it can convert between, e.g. (a+b+c+d) and [a,b,c,d]. 'add/del_portray' make it easy to add and delete clauses for portray. The module also defines ^ as the exponentiation operator. In Poplog, for some reason, although ^ has been defined as an operator (xfy with precedence 10), it is not recognised by "is", which expects **. PUBLIC real( X+ ): "X is a real number". You may have this built-in, possibly under the name of "float". PUBLIC numeric( X+ ): "X is an integer or real". You may have this built-in, possibly under the name of "number". PUBLIC max( A+, B+, C? ): "C is the maximum of A and B". PUBLIC min( A+, B+, C? ): "C is the minimum of A and B". PUBLIC clause_vs_head_tail_pred_arity( Clause?, H?, T?, F?, A? ): "Clause has head H with functor F and arity A, and tail T". If Clause is instantiated, and is not of the form _:-_, then T is unified with 'true', and H with Clause. Going in the reverse direction, if T is 'true', Clause is unified with H and not with H:-true. PUBLIC clause_vs_head_tail( Clause?, H?, T? ): "Clause has head H and tail T". PUBLIC clause_vs_pred_arity( Clause?, P?, A? ): "Clause's head has predicate P and arity A". PUBLIC conj_vs_list( Goals?, List? ): "The list of goals corresponding to Goals is List". E.g. conj_vs_list( (a,b,c), L ) - L = [a,b,c] conj_vs_list( G, [a,b,c] ) - G = (a,b,c) If a goal is 'true', it will be omitted from the list: conj_vs_list( (true,a,b,true,c,true), L ) - L = [a,b,c] PUBLIC round_term_vs_list( Term?, List?, Op+, Ident+ ): This does the same as conj_vs_list, but can accept operators other than comma. E.g. round_term_vs_list( (a+b+c), L, +, '' ). - gives L = [a,b,c] round_term_vs_list( G, [a,b,c], +, '' ). - gives G = a+(b+c) If one of the subterms of Term is Ident, it will be omitted from the list. This is a generalisation of what conj_vs_list does with 'true'. Thus: round_term_vs_list( (0+a+b+0+c+0), L, +, 0 ). - gives L = [a,b,c] PUBLIC abolish( P+, A+ ): "There are no clauses for P/A". Removes all clauses with head predicate P, arity A. PUBLIC is_system_pred( P+, A+ ): True if P/A is a system predicate. PUBLIC is_system_goal( G+ ): True if G calls a system predicate. PUBLIC get_prompt( P? ): Unifies the current prompt used when reading characters or terms interactively to P (as an atom). PUBLIC set_prompt( P+ ): Sets the current prompt used when reading characters or terms interactively to P (as an atom). PUBLIC add_portray( P+ ): "The clause portray(X) :- P(X) has been asserted". If there is no such clause, assert one. PUBLIC del_portray( P+ ): "The clause portray(X) :- P(X) has been deleted". If there is such a clause, delete it. */ /* IMPLEMENTATION -------------- 'real' is missing from Poplog Prolog. It can be implemented easily by calling the built-in routine dataword which tells us what type its argument is. If it's real, dataword will return either 'decimal' or 'ddecimal' (the latter for double-precision reals. If your system lacks such a predicate, but has real numbers, then you can probably do real(X) :- atomic(X), not( integer(X) ), not( atom(X) ). The prompt predicates reset or examine the Poplog system variable prolog_read_prompt which contains the current prompt. If you can't change your read prompt (perhaps by calling a foreign routine and overwriting it), you'll just have to alter the scripts to fit what your system imposes. 'is_system_pred' calls the Poplog predicate 'prolog_system_predicate'. If you don't have such a predicate, you could make a look-up table of all your system predicates (with arities) and check against that. The definition of 'abolish' is commented out because my system has it. 'add/del_portray' call add/del_linking_clause from LIB.PL. Making ^ do exponentiation relies on the fact that in Poplog, the right hand side of "is" can evaluate any functor that's a Pop-11 function name. So all we need do is, in USEFUL.P, to make ^ a function with the same effect as **. ^ is already defined as an operator of the correct fix and precedence. Note that exponentiation is referred to in the lesson on arithmetic; if you don't have ^ as exponentiation, and can't make it, you'll need to change the script. The same goes for "mod" incidentally. */ :- needs add_linking_clause / 3, bug / 2, del_linking_clause / 3. /* USEFUL.P is needed for the prompt. */ :- pop_compile( 'useful.p' ). real(R) :- prolog_eval( dataword(quote(R)), D ), ( D = decimal ; D = ddecimal ), !. numeric(N) :- integer(N), !. numeric(N) :- real(N). max( A, B, C ) :- A >= B, !, C=A. max( A, B, B ). min( A, B, C ) :- A >= B, !, C=B. min( A, B, A ). /* abolish( P, A ) :- functor( Head, P, A ), retractall( Head ). */ clause_vs_head_tail_pred_arity( H, H, true, F, A ) :- H \= ( _ :- _ ), !, functor( H, F, A ). clause_vs_head_tail_pred_arity( (H:-T), H, T, F, A ) :- functor( H, F, A ). clause_vs_head_tail( Clause, H, T ) :- clause_vs_head_tail_pred_arity( Clause, H, T, _, _ ). clause_vs_pred_arity( Clause, P, A ) :- clause_vs_head_tail_pred_arity( Clause, _, _, P, A ). conj_vs_list( C, L ) :- round_term_vs_list( C, L, ',', true ). round_term_vs_list( C, L, Op, Ident ) :- round_term_vs_list( C, [], L, Op, Ident ). round_term_vs_list( G, L0, [G|L0], Op, Ident ) :- functor( Form, Op, 2 ), G \= Form, G \= Ident, !. round_term_vs_list( Ident, L, L, _, Ident ) :- !. round_term_vs_list( Term, L0, L, Op, Ident ) :- functor( Form, Op, 2 ), arg( 1, Form, A ), arg( 2, Form, B ), Term = Form, round_term_vs_list( A, L1, L, Op, Ident ), round_term_vs_list( B, L0, L1, Op, Ident ). is_system_pred( P, A ) :- prolog_system_predicate( P, A ). is_system_goal( G ) :- functor( G, P, A ), is_system_pred( P, A ). get_prompt( P ) :- prolog_eval( apply(valof(get_prompt)), P ). set_prompt( P ) :- not( atom(P) ), bug( 'set_prompt: not an atom', P ). set_prompt( P ) :- prolog_eval( set_prompt(P) ). add_portray(P) :- add_linking_clause( portray, P, 1 ). del_portray(P) :- del_linking_clause( portray, P, 1 ). /* :- endmodule. */