patternjavaMinor
Logic Prolog compiler
Viewed 0 times
compilerprologlogic
Problem
I'm actually doing my own Prolog compiler just like SWISH one with Java. Prolog is a logic language that is particularly suited to programs that involve symbolic or non-numeric computation. Prolog consists of a series of rules and facts. A program is run by presenting some query and seeing if this can be proved against these known rules and facts.
It works with resolving, thanks to the Horn's clauses method, the last line which is called the goal with the first one which have the same litteral.
would give the goal
Another example with the constant predicate
would give the goal
Another example with some arithmetical operations managed by the constant predicate plus and multi
would give with the goal
Or even with the factorial calculation
It would give with the goal go(6).
In our program we load the file in the variable
Our program actually works, but if you have any idea to make it simpler, I would b
It works with resolving, thanks to the Horn's clauses method, the last line which is called the goal with the first one which have the same litteral.
mag(paris,mag_a).
mag(paris,mag_b).
mag(lyon,mag_c).
mag(lyon,mag_d).
listeM(M):-mag(V,M),write(M),write( located_in ),write(V),nl.
listeM(X).would give the goal
listeM(X).: mag_a located_in parisAnother example with the constant predicate
failmag(paris,mag_a).
mag(paris,mag_b).
mag(lyon,mag_c).
mag(lyon,mag_d).
listeM(M):-mag(V,M),write(M),write( located_in ),write(V),nl,fail.
listeM(M):-write(end_list).
listeM(X).would give the goal
listeM(X).:mag_a located_in paris
mag_b located_in paris
mag_c located_in lyon
mag_d located_in lyon
fin liste
true.Another example with some arithmetical operations managed by the constant predicate plus and multi
multi(X,1,X).
multi(X,Y,R):-plus(Y1,1,Y),multi(X,Y1,R1),plus(R1,X,R).
multi(2,3,R),write(R).would give with the goal
multi(2,3,R),write(R)., that is to say searching to multiply 2 and 36Or even with the factorial calculation
fact(1,1).
fact(N,R):-plus(N1,1,N),fact(N1,R1),multi(N,R1,R).
multi(X,1,X).
multi(X,Y,R):-plus(Y1,1,Y),multi(X,Y1,R1),plus(R1,X,R).
go(N):-fact(N,R),write(N),write( has_the_following_factorial ),write(R).
go(6).It would give with the goal go(6).
6 has_the_following_factorial 720
trueIn our program we load the file in the variable
static String fichier ="yourFile.pl"; which has to be at the root of your workspace.Our program actually works, but if you have any idea to make it simpler, I would b
Solution
Parsing is always a bit complicated/ugly in terms of code—a library like ANTLR can do some of the heavy lifting for you. But let's assume some level of reinventing-the-wheel for practice/exercise.
Recommendations
What follows are fairly broad recommendations based on the question: "If I were responsible for maintaining this code, what would I do?"
-
Use lists (expandable) instead of arrays (fixed-length). A number of arrays have sizes that appear arbitrary, such as
-
Add documentation or help code self-document. There are useful comments in the code, but not enough to get a view on what happens where, when, and why. They probably would be enough if the functions and variables could be renamed to signal use or purpose (
-
Reduce the number of static, reachable, mutable references. The abundance of statics greatly widens the conceptual scope of named references, making it harder for human beings to read and reason about the code. Reduce this scope by making them instance references—this will also reduce the number of arrays you need—and by restricting access through
This will be tedious, make no mistake. It will require you to rethink and remodel some parts. But it will greatly improve the ability for people (including yourself!) to reason about the impact of a change to the code.
-
Consider a
-
Add
-
Aim for 1 statement per line, and prefer using braces for code blocks. This is not an unbreakable rule: there are cases where 'packing' statements or blocks is defensible for visual or conceptual reasons. But I'd err on the side of caution.
-
Prefer generics over raw collections. Generics help keep your collections type-safe (reducing bugs) and reduce the number of casts you need.
-
Prefer logging over System.out.print. Java comes with a logging utility (java.util.logging); you can also use one like log4j or slf4j-logback. If this feels like overkill, consider moving
-
Consider
-
Scrutinize
Recommendations
What follows are fairly broad recommendations based on the question: "If I were responsible for maintaining this code, what would I do?"
-
Use lists (expandable) instead of arrays (fixed-length). A number of arrays have sizes that appear arbitrary, such as
Clauses[120] (later redefined to length 100). Unless these lengths represent agreed-upon limits, in which case it would be best to name them through constants (e.g. MAX_CLAUSES), consider using an ArrayList instead. ArrayList has comparable performance to arrays, will grow as needed, and will relieve you of having to store or guess the number of elements.-
Add documentation or help code self-document. There are useful comments in the code, but not enough to get a view on what happens where, when, and why. They probably would be enough if the functions and variables could be renamed to signal use or purpose (
ICF? ri(int noClause)? ).-
Reduce the number of static, reachable, mutable references. The abundance of statics greatly widens the conceptual scope of named references, making it harder for human beings to read and reason about the code. Reduce this scope by making them instance references—this will also reduce the number of arrays you need—and by restricting access through
private where possible.This will be tedious, make no mistake. It will require you to rethink and remodel some parts. But it will greatly improve the ability for people (including yourself!) to reason about the impact of a change to the code.
-
Consider a
Map symbols instead of List listeAff and List listeSymbole. Maps tend to be very fast in lookups, so it will save you processing time. It will also free you from keeping the two lists in sync.-
Add
isInt() to specific classes where needed. All calls to isInt(String) appear to follow the pattern of isInt(Symbole.toString()). Consider adding an instance method isInt() to class Symbole, so that you can change isInt(x.toString()) into x.isInt().-
Aim for 1 statement per line, and prefer using braces for code blocks. This is not an unbreakable rule: there are cases where 'packing' statements or blocks is defensible for visual or conceptual reasons. But I'd err on the side of caution.
-
Prefer generics over raw collections. Generics help keep your collections type-safe (reducing bugs) and reduce the number of casts you need.
-
Prefer logging over System.out.print. Java comes with a logging utility (java.util.logging); you can also use one like log4j or slf4j-logback. If this feels like overkill, consider moving
if (...) System.out.println(...) to methods like debug(String) to reduce clutter.-
Consider
switch-case instead of if-else chains comparing to constants. ri(int) is an example where switch-case would probably both be faster and clearer.-
Scrutinize
extends LinkedList. You'll probably need only two or three of its methods, so you might get away with adding the methods explicitly, and then delegating to a private field. If these classes do need to be list-like, consider adding the List interface instead, and then delegate, or add a method List asList() that provides a view of what you need.Context
StackExchange Code Review Q#127323, answer score: 2
Revisions (0)
No revisions yet.