I love this tip from Markus Triska, who attributes it to Ulrich Neumerkel:
:- op(920,fy, *).
*_.
As a tool to isolate errors in code. But I don’t understand what the second specification is doing. After defining the unary operator, I would expect something like the following, to specify the semantics of the operator:
“Declarative program development in Prolog” with GUPU by Ulrich Neumerkel and Stefan Kral (PDF)
“Localizing and explaining reasons for non-terminating logic programs with failure-slices” by Ulrich Neumerkel and Fred Mesnard (PDF)
While I am aware of the concept I don’t use it enough to answer more questions.
As you’ve noted, the directive :- op(920, fy, *) defines * as an unary prefix operator. This precisely means that we can use * as a functor by putting it in front of other terms, without using the usual parentheses. So *_. is the same as * _. which is the same as *(_)., '*'(_)., etc.
I looked on StackOverflow for failure-slice by Ulrich but didn’t see anything for *_ – did I miss something? (The papers look interesting, but will take some work for me to understand)
That’s a good article. It introduces the concept of generalisation and specialisation of a logic program, or a definite clause, that is central to Logic Programming and to Inductive Logic Programming (ILP). In fact all ILP approaches work on the basis of this concept: they either start with a program that is over-general and specialise it, or with one that is over-special and generalise it, or do both in tandem. Like Markus points out, that is only possible in a logic programming language like Prolog where programs are sets of clauses and clauses are sets of literals, so changing the semantics of a program is a simple matter of adding or removing a literal or a clause; which is also what makes ILP computationally hard! Good stuff, Markus. And I see a reference to one of the two foundational texts of ILP, Ehud Shapiro’s doctoral thesis (Algorithmic Program Debugging).