Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Would a Prolog expert please explain the difference between > and #>, is and #=, and what ! does?

The version without ! looks identical to the version with ! except only the ! is removed - is this a joke?



Prolog operators like `4 > 5` are a syntax sugar which desugars into a normal function call `>(4, 5)`. This part of the language is programmable, so you can add your own function `#>(X, Y)` and then declare it as an operator and use it like `4 #> 5`. See [1]. Nitpickingly, this means we can't be sure what #> is without looking, but it's common in Scryer and SWI Prolog (at least) that the #> #< versions of numeric comparison operators are used by constraint solver libraries. In imaginary Python it might be this code:

    import solver

    solver.add_variable(x)
    solver.variable_range(x, 0, 100)
    solver.add_constraint(x, greater_than, 50)

    solver.solve_for(x)
in pseudo-Prolog it can be:

    :- using constraint solver library
    
    X in 0..100,
    X #> 50,

    label(X)
where "in" and "#>" were added into the language at runtime by the import of the constraint library. That is, it calls out to a custom 'function' which tells the constraint solver to restrict possible values for for X from 0..100 down to 51..100.

> "and what ! does"

This is a concept which doesn't translate easily to other languages, but analogously it's like the performance difference between this code which always searches the entire haystack:

    found = false
    for item in haystack:
        if item == 'needle':
            found = true

    return found
and this which stops searching the haystack if the needle is found, but still searches the entire haystack in the worst case:

    for item in haystack:
        if item == 'needle':
            return true

    return false
The catch being that ! is not exactly a performance thing, it's an instruction to the Prolog runtime to skip some of the code, which can speed up performance but if you throw it in carelessly, your code no longer gives the right answers.

[1] They aren't Prolog "functions", they are predicates, functions are different, but it will do for this explanation.


!/0 is the cut. It prunes the search space. Useful to say "do not look at the other alternatives since I know they will fail" (when mutually exclusivity is hard) but also necessary to do negation in Prolog (when negated information cannot be easily or efficiently propagated).

is/2 is arithmetic evaluator. It runs only in one direction and it does not solve equations.

#>, #=, etc. are constraints, like (in)equalities over linear arithmetic. When constraints have the form of some known theory (like in SMT solvers), they can be solved (incrementally). That is called "constraint logic programming" (CLP). Modern Prolog systems are indeed CLP systems.

Prolog is older than CLP. CLP is older than SMT. Prolog+CLP systems are turing complete, can be used as programming languages. SMT is powerful but not a programming language.

Can "impure" features be avoided? Not in all cases. Think of them as 'unsafe' in Rust, but less dangerous.

Markus pushes for more purity in Prolog (using CLPFD), but sometimes some impurity (or imperative-like code with side-effects) is the best solution. Sometimes the pure solution is also the better. In other cases, it is not. Better compilers and static analyzers can reduce the friction between these worlds.

Take away: do pure code if you can afford it and it looks like a natural solution to your problem, use impure features later if you really need them.


I think in many real-life cases it's a mix - for example impure code that deals with the outside world to set up the data needed for the pure "core" of the app to run over.



>> The version without ! looks identical to the version with ! except only the ! is removed - is this a joke?

That's just showing getting rid of the cut in two stages. The line that makes it possible to remove it is this one:

N #> 0,

Markus Triskas' argument is that if you use the #> etc versions of declarative arithmetic operators, instead of the > ones, you can then call the factorial predicate with both arguments as variables, i.e. without inputs, just outputs, to enumerate the entire factorial relation. Like this:

  ?- n_factorial(N, F).
     N = 0, F = 1
  ;  N = 1, F = 1
  ;  N = 2, F = 2
  ;  N = 3, F = 6
  ;  ... .
If you use > instead of #> the line N > 0 will raise an exception if N is a variable, which will be the case if you call it as above. This stops you from enumerating the relation, which declarative arithmetic allows.

Of course there are other ways to write a factorial predicate (or any predicate) so that it always enumerates a relation but they are more verbose. Then again, you do need a special library to use declarative arithmetic anyway, so.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: