s-webber / projog Goto Github PK
View Code? Open in Web Editor NEWProlog programming for the Java platform.
License: Apache License 2.0
Prolog programming for the Java platform.
License: Apache License 2.0
Currently arithmetic functions are configured using just their name (e.g. +
, -
and *
).
For higher granularity, and to be consistent with predicates, arithmetic functions could be configured by a combination of both their name and arity (i.e. number of arguments they accept).
e.g.: -/2
(i.e. subtraction) and -/1
(i.e. minus)
findall/3
provides a single list containing all solutions to the specified goal.
Example:
?- findall(Y, (member(X,[6,3,7,2,5,4,3]), X<4, Y is X*X), L).
L = [9, 4, 9].
The current pattern for implementing new predicates is to implement public boolean evaluate(Term... args)
of Predicate
.
For performance reasons (to avoid the overhead of compiled predicates having to create a new Term[]
every time they call evaluate
) it is also common practice for predicates to create an overloaded version which accepts the exact number of arguments required - that the evaluate(Term...)
varargs version (which is still used in interpreted, rather than compiled, mode) then delegates to.
Example:
public class SingletonPredicateExample extends AbstractSingletonPredicate {
@Override
public boolean evaluate(Term... args) {
return evaluate(args[0]);
}
/**
* Overloaded version of {@link #evaluate(Term...)} that avoids the overhead of creating a new {@code Term} array.
*
* @see org.projog.core.Predicate#evaluate(Term...)
*/
public boolean evaluate(Term arg) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
String currentDate = sdf.format(new Date());
return arg.unify(new Atom(currentDate));
}
}
It would be more convenient if it was possible to just create an overloaded version of evaluate
that accepts the exact number of arguments that the predicate requires. (i.e. Don't implement the varargs version each time.)
e.g. public boolean evaluate()
(for a predicate that does not accept any arguments - e.g. true
) or public boolean evaluate(Term arg1, Term arg2, Term arg3)
(for a predicate that accepts 3 arguments - e.g. bagof/3
)
First argument is a list of key/value pairs represented using a hypen (i.e. -
) as the functor (e.g. key-value).
Predicate will sort list by key of pairs and unify result with second argument.
Example use:
?- keysort([a - 1,b - 3,c - 2], X).
X = [a-1, b-3, c-2].
?- keysort([c - 2,a - 1, b - 3], X).
X = [a-1, b-3, c-2].
not
is a synonym for the existing \+
predicate.
It would be convenient if both not
and \+
were supported by Projog (providing the same functionality).
Currently supported:
?- \+ true.
false.
?- \+ false.
true.
Currently unsupported:
?- not(true).
false.
?- not(false).
true.
When being called with two integer arguments the /
arithmetic function currently behaves in the same way as the //
function (see #25) does - this is incorrect when the exact result is not an integer.
Current (incorrect) behaviour:
?- X is 6 / 2.
X = 3.
?- X is 7 / 2.
X = 3.
Correct behaviour:
?- X is 6 / 2.
X = 3.
?- X is 7 / 2.
X = 3.5.
Attempts to unify the third argument with a version of the list represented by the first argument with any occurrences of the second argument removed.
Examples:
?- delete([h,e,l,l,o], l, X).
X = [h, e, o].
?- delete([h,e,l,l,o], X, Y).
Y = [].
?- X=p(A,b,e), delete([p(_,_,_),p(a,B,c),p(q,B,e),p(z,b,W)], X, Y).
X = p(A, b, e),
Y = [p(a, B, c)].
The following query:
?- X=true, X.
Produces the following error:
Expected an atom or a predicate but got a NAMED_VARIABLE with value: X
This is not the correct behavior - the correct behavior is for the query to evaluate successfully once.
Full stacktrace:
org.projog.core.ProjogException: Expected an atom or a predicate but got a NAMED_VARIABLE with value: X
at org.projog.core.PredicateKey.createForTerm(PredicateKey.java:58)
at org.projog.core.KnowledgeBase.getPredicateFactory(KnowledgeBase.java:199)
at org.projog.core.function.compound.Conjunction.getPredicate(Conjunction.java:174)
at org.projog.core.function.compound.Conjunction.getPredicate(Conjunction.java:163)
at org.projog.core.function.compound.Conjunction.getPredicate(Conjunction.java:139)
at org.projog.api.QueryResult.next(QueryResult.java:70)
at org.projog.tools.ProjogConsole.evaluateOnce(ProjogConsole.java:183)
at org.projog.tools.ProjogConsole.parseAndExecute(ProjogConsole.java:121)
at org.projog.tools.ProjogConsole.run(ProjogConsole.java:75)
at org.projog.tools.ProjogConsole.main(ProjogConsole.java:222)
True if a sorted version of list represented by the first argument can be unified with the second argument.
NOTE: Similar to msort/2
(see #50) - but, unlike msort/2
, sort/2
does remove duplicates.
Example:
?- sort([q,w,e,r,t,y],X).
X = [e, q, r, t, w, y].
?- sort([h,e,l,l,o],X).
X = [e, h, l, o].
integer(X) is true when X is bound to an integer, else false.
Examples:
?- integer(0).
true.
?- integer(1).
true.
?- integer(-1).
true.
?- integer(76832).
true.
?- integer(1.0).
false.
?- integer("1").
false.
?- integer(1+1).
false.
reverse(X,Y) succeeds if the elements of list X are in reverse order compared to the elements of list Y
length(X,Y) is true when the integer Y is equal to the number of elements in list Y
Example use:
?- length([a,b,c],X).
X = 3.
?- length([],X).
X = 0.
member(E, L) succeeds if E is a member of the list L.
Unlike "memberchk(E, L)", an attempt is made to retry the goal during backtracking - so it can be used to enumerate the members of a list.
Example use:
?- member(a,[a,b,c]).
true .
?- member(b,[a,b,c]).
true ;
false.
?- member(a,[a,b,c]).
true ;
false.
?- member(b,[a,b,c]).
true ;
false.
?- member(c,[a,b,c]).
true.
?- member(d,[a,b,c]).
false.
?- member(X,[a,b,c]).
X = a ;
X = b ;
X = c.
?- member(a,[a,a,a]).
true ;
true ;
true.
Currently it is possible to create structures that have no arguments. e.g.:
?- X = p().
X = p().
According to the rules of Prolog, this should not be allowed - structures must always have at least one argument (e.g. p(a)
).
Example:
13 ?- repeat, X is random(7).
X = 4 ;
X = 6 ;
X = 5 ;
X = 2 ;
X = 0 ;
X = 1 ;
The **
arithmetic function calculates the first argument raised to the power of the second argument.
Examples:
?- X is 2**5.
X = 32.
?- X is 5**3.
X = 125.
atom_concat(X, Y, Z) attempts to unify Z with the concatenation of X and Y
Examples:
Final argument is a variable:
?- atom_concat(abc, def, X).
X = abcdef.
One of the first two arguments is a variable:
?- atom_concat(abc, X, abcdef).
X = def.
?- atom_concat(X, def, abcdef).
X = abc.
Both of the first two arguments are variables:
40 ?- atom_concat(X, Y, abc).
X = '',
Y = abc ;
X = a,
Y = bc ;
X = ab,
Y = c ;
X = abc,
Y = ''.
Example use:
?- append(X, Y, [1,2,3,4]).
X = [],
Y = [1, 2, 3, 4] ;
X = [1],
Y = [2, 3, 4] ;
X = [1, 2],
Y = [3, 4] ;
X = [1, 2, 3],
Y = [4] ;
X = [1, 2, 3, 4],
Y = [] ;
false.
?- append([1,2],[3,4],[1,2,3,4]).
true.
?- append([1,2],[3,4],Z).
Z = [1, 2, 3, 4].
?- append([1,2|q],[3,4],Z).
false.
?- append([1,2],[3,4|y],Z).
Z = [1, 2, 3, 4|y].
Currently org.projog.core.KnowledgeBase
has an instance of org.projog.core.function.io.Write
as a member variable.
I think the functionality that KnowledgeBase
uses Write
to provide could be provided by another class.
Removing Write
from KnowledgeBase
would have the benefits of:
KnowledgeBase
.KnowledgeBase
relies on.Example use:
?- flatten([a,[[b]],[c]],X).
X = [a, b, c].
Example use:
?- subtract([a,b,c,d,e,f], [a,s,d,f], X).
X = [b, c, e].
Add nth0/3
built-in predicate which checks the term (3rd argument) at the specified index (first argument) of the specified list (second argument).
Example use:
?- nth0(1, [h, e, l, l, o], Z).
Z = e.
?- nth0(X, [h, e, l, l, o], l).
X = 2 ;
X = 3 ;
false.
?- nth0(X, [h, e, l, l, o], z).
false.
?- nth0(X, [h, e, l, l, o], Z).
X = 0,
Z = h ;
X = 1,
Z = e ;
X = 2,
Z = l ;
X = 3,
Z = l ;
X = 4,
Z = o.
True if first argument is a subset of the second argument.
Examples:
?- subset([a,d,e],[a,b,c,d,e,f]).
true.
?- subset([a,d,e,z],[a,b,c,d,e,f]).
false.
?- subset([a,d,e,a],[a,b,c,d,e,f]).
true.
?- subset([p(X),p(X)],[p(a),p(b),p(c)]).
X = a.
?- subset([p(a),p(b)],[p(X),p(X),p(c)]).
false.
Attempts to unify the third argument with the result of removing one instance of first argument from the list represented by the second argument.
Examples:
?- select(X,[h,e,l,l,o],Z).
X = h,
Z = [e, l, l, o] ;
X = e,
Z = [h, l, l, o] ;
X = l,
Z = [h, e, l, o] ;
X = l,
Z = [h, e, l, o] ;
X = o,
Z = [h, e, l, l] ;
?- select(l,[h,e,l,l,o],Z).
Z = [h, e, l, o] ;
Z = [h, e, l, o] ;
false.
?- select(l,[h,e,l,l,o],[h,e,l,o]).
true ;
true ;
false.
?- select(p(a,B),[p(X,q), p(a,X)],Z).
B = q,
X = a,
Z = [p(a, a)] ;
B = X,
Z = [p(X, q)] ;
false.
True if a sorted version of list represented by the first argument can be unified with the second argument.
NOTE: Similar to sort/2
(see #42) - but, unlike sort/2
, msort/2
does not remove duplicates.
Example:
?- msort([q,w,e,r,t,y],X).
X = [e, q, r, t, w, y].
?- msort([h,e,l,l,o],X).
X = [e, h, l, l, o].
compound(X) is true when X is bound to a compound term.
Currently classes that implement built-in predicates are tested using queries contained in their comments (specified using Prolog syntax) and documented in the "Prolog Commands" section of the manual. Both the testing and documentation happen automatically as part of the Ant build process.
It would be nice if this functionality was extended to also support arithmetic functions (i.e. instances of Calculatable
).
ensure_loaded/1
is equivalent to the existing consult/1
built-in predicate.
(In other Prolog implementations (e.g. SWI) ensure_loaded/1
does have behaviour distinct from consult/1
when dealing with module files - but as Projog does not (yet) support the concept of modules, for the time being ensure_loaded/1
can be simply a synonym for consult/1
.)
Compares second and third arguments.
>
<
=
Examples:
?- compare(X, a, z).
X = (<).
?- compare(X, a, a).
X = (=).
?- compare(X, z, a).
X = (>).
?- compare(<, z, a).
false.
?- compare(>, z, a).
true.
memberchk(X, Y) returns true if X is an element of the list Y
(Unlike "member(X, Y)", no attempt is made to re-evaluate during backtracking.)
Example use:
?- memberchk(a,[a,b,c]).
true.
?- memberchk(b,[a,b,c]).
true.
?- memberchk(c,[a,b,c]).
true.
?- memberchk(d,[a,b,c]).
false.
?- memberchk(a,[a,b,a,c]).
true.
?- memberchk(X,[a,b,a,c]).
X = a.
An exception is thrown when retrying queries that contain a cut (i.e. !
).
Current (incorrect behaviour):
?- repeat, !.
yes (1 ms);
Caught: org.projog.core.CutException from class: org.projog.core.CutException method: <clinit> line: 22
Correct behaviour:
?- repeat, !.
yes (0 ms);
no (0 ms)
Finds solutions for the specified goal. The resulting list will be ordered using the standard ordering of terms - and will exclude duplicates. Can succeed on backtracking. Fails if the specified goal cannot be satisfied.
Example:
?- setof(Y, (member(X,[6,3,7,2,5,4,3]), X<4, Y is X*X), L).
X = 2,
L = [4] ;
X = 3,
L = [9].
Allows user-defined predicates to be used as arithmetic functions.
Finds solutions for the specified goal. The elements in the resulting list will appear in the order they were found and may include duplicates. Can succeed on backtracking. Fails if the specified goal cannot be satisfied.
Example:
?- bagof(Y, (member(X,[6,3,7,2,5,4,3]), X<4, Y is X*X), L).
X = 2,
L = [4] ;
X = 3,
L = [9, 9].
Current (incorrect) behaviour when the predicate name is the same as an infix operator:
?- X = +(1,1).
Error parsing query:
Expected . but got: ,(1, 1) after: ?-(=(X, +))
?-X = +(1,1).
^
Current (incorrect) behaviour when the predicate name is not the same as an infix operator:
?- X = ~(1,1).
Error parsing query:
invalid command: ~(
?-X = ~(1,1).
^
Correct behaviour:
?- X = +(1, 1).
X = 1 + 1
yes (0 ms)
Note: it does currently work if the predicate name is quoted (e.g. ?- X = '+'(1,1).
).
As well as Java unit-tests written using JUnit, Projog also supports "system tests" written in Prolog - where queries, and their expected results, are specified in comments (i.e. prefixed by %
).
These tests are located in the scripts
directory and in comments contained in Java code.
An example of how these tests are constructed (taken from Call.java) is shown below:
/* SYSTEM TEST
% %TRUE% call(true)
% %FALSE% call(fail)
% %QUERY% X = true, call(X)
% %ANSWER% X = true
% %FALSE% X = fail, call(X)
test(a).
test(b).
test(c).
% %QUERY% X = test(Y), call(X)
% %ANSWER%
% X = test(a)
% Y = a
% %ANSWER%
% %ANSWER%
% X = test(b)
% Y = b
% %ANSWER%
% %ANSWER%
% X = test(c)
% Y = c
% %ANSWER%
testCall(X) :- call(X).
% %FALSE% testCall(fail)
% %TRUE% testCall(true)
% %QUERY% testCall((true ; true))
% %ANSWER/%
% %ANSWER/%
*/
Is it possible to make the syntax, included in the comments used to construct these tests, more concise?
Example (showing difference between \\
and \
):
?- X is 6 / 2.
X = 3.
?- X is 6 // 2.
X = 3.
?- X is 7 / 2.
X = 3.5.
?- X is 7 // 2.
X = 3.
The HTML documentation, generated by the build process, does not include the subtract/3
built-in predicate.
I think the problem is that there are two classes (in different packages) that have the name Subtract
(one is for the arithmetic function and the other is for the list operation).
The class name (minus the package) of a document-able class is used as the file name of the corresponding HTML page. If two classes have the same name then, when the document generation process is run, the documentation of the second one found will overwrite the documentation of the first.
The way that pj_add_predicate/2
is currently implemented means it is not included in the system testing or documentation processes of the Ant build script.
It would be good is this could be corrected by implementing pj_add_predicate/2
in a way that is consistent with the other built-in predicates.
When using Java 8, the testScriptGeneration test of CompiledPredicateSourceGeneratorTest fails due to:
[junit] java.lang.RuntimeException: Comparing scripts\CompiledPredicateSourceGeneratorTest\CallCompiledEvaluatable.txt to build\org.projog.core.udp.compiler.CompiledPredicateSourceGeneratorTest\org\projog\content_generated_at_runtime\CompiledPredicate3.java caused java.lang.RuntimeException: [v0_B = _0;] in CallCompiledEvaluatable.txt not equals to [v0_C = _0;] in CompiledPredicate3.java line 27
I suspect this is due to difference in java.util.HashSet ordering between Java 8 and earlier versions.
I think the solution is to change the getVariablesToKeepTempVersionOf method of CompiledPredicateWriter to use a LinkedHashSet (so can guarantee consistent ordering regardless of Java version).
Example use:
?- is_list([]).
true.
is_list([a,b]).
true.
?- is_list([a|b]).
false.
?- is_list([a|[]]).
true.
?- is_list(X).
false.
The mod arithmetic function is currently implemented in Projog by using Java's %
operator - this is not the intended behaviour of the mod function in Prolog.
Current (incorrect) behaviour:
?- X is 2 mod -5.
X = 2
Correct behaviour:
?- X is 2 mod -5.
X = -3.
?- X is 2 rem -5.
X = 2.
Consulting a file containing the following:
test(X) :- X.
Causes the following error:
Expected an atom or a predicate but got a NAMED_VARIABLE with value: X
Full stacktrace:
Could not read prolog source from file: test.pl due to: org.projog.core.ProjogException: Expected an atom or a predicate but got a NAMED_VARIABLE with value: X
org.projog.core.ProjogException: Expected an atom or a predicate but got a NAMED_VARIABLE with value: X
at org.projog.core.PredicateKey.createForTerm(PredicateKey.java:58)
at org.projog.core.KnowledgeBase.getPredicateFactory(KnowledgeBase.java:199)
at org.projog.core.udp.interpreter.ClauseActionFactory.getClauseAction(ClauseActionFactory.java:43)
at org.projog.core.udp.StaticUserDefinedPredicateFactory.createClauseActionsFromClauseModels(StaticUserDefinedPredicateFactory.java:115)
at org.projog.core.udp.StaticUserDefinedPredicateFactory.setCompiledPredicateFactory(StaticUserDefinedPredicateFactory.java:101)
at org.projog.core.udp.StaticUserDefinedPredicateFactory.compile(StaticUserDefinedPredicateFactory.java:94)
at org.projog.core.ProjogSourceReader.addUserDefinedPredicatesToKnowledgeBase(ProjogSourceReader.java:227)
at org.projog.core.ProjogSourceReader.parse(ProjogSourceReader.java:147)
at org.projog.core.ProjogSourceReader.parseFile(ProjogSourceReader.java:59)
at org.projog.api.Projog.consultFile(Projog.java:158)
at org.projog.tools.ProjogConsole.consultScript(ProjogConsole.java:109)
at org.projog.tools.ProjogConsole.consultScripts(ProjogConsole.java:102)
at org.projog.tools.ProjogConsole.run(ProjogConsole.java:66)
at org.projog.tools.ProjogConsole.main(ProjogConsole.java:222)
Expected an atom or a predicate but got a NAMED_VARIABLE with value: X
writef/2
is similar to Java's System.out.format
.
The first argument is a string text containing format specifiers, the format specifiers are replaced with arguments provided and the result output to the output stream.
Example:
?- writef("example: %t %t %t", [a,1,p(z)]).
example: a 1 p(z)
There are a collection of 99 Prolog Problems hosted at:
https://sites.google.com/site/prologsite/prolog-problems
What is required to make the provided solutions to these problems work with Projog?
i.e. What functionality required by the solutions is not already provided by the built-in predicates and arithmetic functions of Projog?
X = Y is true when X and Y are not unifiable, else false. (i.e. Only evaluates to true if terms are not Prolog unifiable.)
Example use:
?- a \= b.
true.
?- a \= a.
false.
?- a \= X.
false.
First argument is minimum value in range, second argument is maximum value in range.
True if third argument is greater than or equal to integer represented by first argument and less than or equal to the integer represented by the second argument.
Example:
?- between(1, 5, 0).
false.
?- between(1, 5, 1).
true.
?- between(1, 5, 3).
true.
?- between(1, 5, 5).
true.
?- between(1, 5, 6).
false.
?- between(1, 5, X).
X = 1 ;
X = 2 ;
X = 3 ;
X = 4 ;
X = 5.
float(X) is true when X is bound to a floating point number, else false.
Examples:
?- float(0.0).
true.
?- float(1.0).
true.
?- float(-1.0).
true.
?- float(76832.46).
true.
?- float(1).
false.
?- float("1.5").
false.
?- float(1.25+1.75).
false.
Current (incorrect) behaviour:
?- X is 7 * 4 // 2.
org.projog.core.ProjogException: Expected integer but got: STRUCTURE with value: *(7, 4)
Correct behaviour:
?- X is 7 * 4 // 2.
X = 14
yes (16 ms)
Full stack trace:
org.projog.core.ProjogException: Expected integer but got: STRUCTURE with value: *(7, 4)
at org.projog.core.term.TermUtils.toInt(TermUtils.java:131)
at org.projog.core.function.math.IntegerDivide.calculate(IntegerDivide.java:19)
at org.projog.core.function.math.IntegerDivide.calculate(IntegerDivide.java:16)
at org.projog.core.CalculatableFactory.getNumeric(CalculatableFactory.java:53)
at org.projog.core.KnowledgeBase.getNumeric(KnowledgeBase.java:115)
at org.projog.core.function.math.Is.evaluate(Is.java:63)
at org.projog.core.function.math.Is.evaluate(Is.java:54)
at org.projog.api.QueryResult.doFirstEvaluationOfQuery(QueryResult.java:66)
at org.projog.api.QueryResult.next(QueryResult.java:53)
at org.projog.tools.ProjogConsole.evaluateOnce(ProjogConsole.java:168)
at org.projog.tools.ProjogConsole.parseAndExecute(ProjogConsole.java:106)
at org.projog.tools.ProjogConsole.run(ProjogConsole.java:60)
at org.projog.tools.ProjogConsole.main(ProjogConsole.java:207)
Calls the goal represented by a term - no attempt is made to retry the goal during backtracking.
Example use:
?- once(true).
true.
?- once(fail).
false.
?- once(repeat).
true.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.