Friday 22 June 2007

Examples of two useful predicates

Two of DW's most useful predicates are assign(A,B,C) and call(A,B,C).
Here's a good rundown I was given on how to use them.

Given the following code example
c = a.lookup()

we have call(A,B,C) where A is a.lookup(), B is lookup() and C is a
and assign(A,B,C) where A is c = X (where X is the return value of a.lookup), B is c and C is a.lookup()

Sunday 17 June 2007

DIY - How to build your own DW predicate

1. Check that you don't already have the tools to write the predicate in terms of other Prolog predicates. Existing predicate wrappings are stored in natives.dw and using existing Prolog predicates is quicker and easier than writing your own (usually).

2. If there isn't you'll need to create a new class file in the dw.predicate package that extends PredicateMatcher, with a suitably descriptive name. You'll need to add a PredicateFactory to the end of this class too, this allows the engine to construct new copies of your predicate as required. Remember that your constructor must reset your predicate to a fresh state, so if you're using any class variables they need to be reset in the constructor. Use PredicateFactory's of other predicate class files as examples.

3. Think about the cases you'll need to cater for. Take for example the predicate imaginary(x,y). You'll need 4 cases, one for when both parameters are bound, two for when only one is bound, and a final one for when both are unbound. Test param(0).isFree() to see whether each paramater is bound or not, and select in an if block. Some cases won't apply, in which case you may either throw an execption or return false.

4. When building each predicate case, you'll need to getValue() on each bound parameter and cast it to an instance of some of the types you expect. The types are listed in dw.type, but generally your incoming variable will be a CodeValue or a CodeUnit. Use instanceof to deal with the various types, and use unify to attempt to resolve unbound predicates, using the boolean result of unify as a return value.

5. Bind the predicate to the classfile natively in natives.dw, to do this simple add
native imaginary(x,y) = "dw.predicate.Imaginary" (or whatever you called your class file)

6. Test the results! If it doesn't work, use the print(x) Prolog predicate as a simple aid to diagnosis, the most usual causes are accidentally leaving a variable unbound that you thought was bound, or sending in an instance of an unexpected type.

Tips:
  • Even though DW's types are currently a wrapping over soot, its usually better to use their built in methods than going straight to soot. They're there for a reason!
  • Throw your exceptions rather than returning false where possible, it's much easier to diagnose unexpected behaviour this way.