1

I'm implementing a Prolog interpreter, and I'd like to include some built-in mathematical functions (sum, product, etc). For example, I would like to be able to make calculations using knowledge bases like this one:

NetForce(F) :- Mass(M), Acceleration(A), Product(M, A, F)
Mass(10) :- []
Acceration(12) :- []

So then I should be able to make queries like ?NetForce(X). My question is: what is the right way to build functionality like this into my interpreter?

In particular, the problem I'm encountering is that, in order to evaluate Sum, Product, etc., all their arguments have to be evaluated (i.e. bound to numerical constants) first. For example, while to code above should evaluate properly, the permuted rule:

NetForce(F) :- Product(M, A, F), Mass(M), Acceleration(A)

wouldn't, because M and A aren't bound when the Product term is processed. My current approach is to simply reorder the terms so that mathematical expressions appear last. This works in simple cases, but it seems hacky, and I would expect problems to arise in situations with multiple mathematical terms, or with recursion. Is there a better solution?

user1604015
  • 415
  • 2
  • 9
  • 1
    I'd suggest: Use an existing Prolog system to build your extensions as meta-interpreters. – false Nov 14 '13 at 20:49
  • See http://stackoverflow.com/questions/14527682/implementing-prolog-in-c-or-c/14536068#14536068 – false Nov 14 '13 at 20:50
  • Yeah, I think that would make sense, but I'm not sure if it will work in the larger context of my project. I'll look into it. – user1604015 Nov 14 '13 at 20:57
  • 1
    Your prolog syntax is off - predicates need to start with lowercase letters, and the `:- []` part is invalid syntax... – l4mpi Nov 14 '13 at 21:03
  • The example is from the interpreter I have. It's not supposed to work in an existing Prolog system. – user1604015 Nov 14 '13 at 21:09

3 Answers3

2

The functionality you are describing exists in existing systems as constraint extensions. There is CLP(Q) over the rationals, CLP(R) over the reals - actually floats, and last but not least CLP(FD) which is often extended to a CLP(Z). See for example library(clpfd).

In any case, starting a Prolog implementation from scratch will be a non-trivial effort, you will have no time to investigate what you want to implement because you will be inundated by much lower level details. So you will have to use a more economical approach and clarify what you actually want to do.

You might study and implement constraint languages in existing systems. Or you might want to use a meta-interpreter based approach. Or maybe you want to implement a Prolog system from scratch. But don't expect that you succeed in all of it.

And to save you another effort: Reuse existing standard syntax. The syntax you use would require you to build an extra parser.

false
  • 10,264
  • 13
  • 101
  • 209
  • 1
    Got it. I think I'll start be at least looking into implementing the required constraint machinery. Do you have recommendations for resources on this? – user1604015 Nov 14 '13 at 21:07
  • 1
    SWI-Prolog (opensrc) and SICStus (commercial) haave it all + CHR, when etc. – false Nov 14 '13 at 21:10
1

You could use coroutining to delay the evaluation of the product:

product(X, A, B) :- freeze(A, freeze(B, X is A*B))

freeze/2 delays the evaluation of its second argument until its first argument is ground. Used nested like this, it only evaluates X is A*B after both A and B are bound to actual terms.

(Disclaimer: I'm not an expert on advanced Prolog topics, there might be an even simpler way to do this - e.g. I think SICStus Prolog has "block declarations" which do pretty much the same thing in a more concise way and generalized over all declarations of the predicate.)

l4mpi
  • 5,103
  • 3
  • 34
  • 54
  • (when)/2 -declarations are most apt if you want to literally reuse (is)/2. But constraints are much better. – false Nov 14 '13 at 21:11
  • @false AFAIK the SICStus block declarations are an improved `when` declaration, and are heavily used for implementing constraint solving. So if OP is trying to implement his own constraint system they might be helpful. – l4mpi Nov 14 '13 at 21:24
  • And AFAIK, `block` declarations were present prior to the built-in `when/2` and before that, `wait` declarations featured SICStus 0.7. In any case, implementing a constraint **system** solely based on any of those constructs leads to **weak** consistency and cannot be recommended. – false Nov 14 '13 at 23:22
  • In any case: it is trivial to implement `block` declarations with `when/2`. It is **impossible** to implement `when/2` with `block` declarations. So it is not clear what you meant by "improved `when` declarations". – false Nov 14 '13 at 23:25
  • @false you're right, I meant `wait` declarations where I wrote `when` declarations - as I said, I'm by no means an expert on these topics. The comment about the constraint system is taken from the [ProB](http://www.stups.hhu.de/ProB/index.php5/Why_Prolog%3F) documentation (see 3rd bullet point), which is somewhat ambiguous as it also talks about `when`, but a further comment suggests they also use block declarations. – l4mpi Nov 14 '13 at 23:42
  • Scimmed ProB: Expect signification speedup in [4.3 with JIT](http://sicstus.sics.se/comingfeatures.html) – false Nov 15 '13 at 00:05
0

Your predicates would not be clause order independent, which is pretty important. You need to determine usage modes of your predicates - what will the usage mode of NetForce() be? If I were designing a predicate like Force, I would do something like

force(Mass,Acceleration,Force):- Force is Mass * Acceleration.

This has a usage mode of +,+,- meaning you give me Mass and Acceleration and I will give you the Force.

Otherwise, you are depending on the facts you have defined to unify your variables, and if you pass them to Product first they will continue to unify and unify and you will never stop.

C.B.
  • 8,096
  • 5
  • 20
  • 34
  • So is the idea that the usage mode - roughly - does something like determining the order of evaluation? – user1604015 Nov 14 '13 at 21:00
  • Well your query ?NetForce(X) is a generator, it is attempting to generate values to assign X to. Is this your intent? I mean, because then literally any integer value would be a correct unification. – C.B. Nov 14 '13 at 21:38